Merge "Check to see if the power source is a valid charger."
diff --git a/Android.mk b/Android.mk
index b171dbd..c08be7f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,6 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LIBRARIES := bouncycastle
 LOCAL_STATIC_JAVA_LIBRARIES := guava
 
 LOCAL_MODULE_TAGS := optional
diff --git a/res/drawable-hdpi/ic_emergency.png b/res/drawable-hdpi/ic_emergency.png
new file mode 100644
index 0000000..89c05e3
--- /dev/null
+++ b/res/drawable-hdpi/ic_emergency.png
Binary files differ
diff --git a/res/drawable-hdpi/stat_sys_phone_call.png b/res/drawable-hdpi/stat_sys_phone_call.png
new file mode 100755
index 0000000..9b5f075
--- /dev/null
+++ b/res/drawable-hdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_emergency.png b/res/drawable-mdpi/ic_emergency.png
new file mode 100755
index 0000000..c6faf1e
--- /dev/null
+++ b/res/drawable-mdpi/ic_emergency.png
Binary files differ
diff --git a/res/drawable-mdpi/stat_sys_phone_call.png b/res/drawable-mdpi/stat_sys_phone_call.png
new file mode 100644
index 0000000..c44d062
--- /dev/null
+++ b/res/drawable-mdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/res/drawable/data_sweep_left.xml b/res/drawable/data_sweep_left.xml
index cb801a0..3532cbc 100644
--- a/res/drawable/data_sweep_left.xml
+++ b/res/drawable/data_sweep_left.xml
@@ -15,6 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:enterFadeDuration="@android:integer/config_mediumAnimTime"
     android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_left_activated" />
diff --git a/res/drawable/data_sweep_limit.xml b/res/drawable/data_sweep_limit.xml
index 378b0aa..cfdbfbb 100644
--- a/res/drawable/data_sweep_limit.xml
+++ b/res/drawable/data_sweep_limit.xml
@@ -15,6 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:enterFadeDuration="@android:integer/config_mediumAnimTime"
     android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_limit_activated" />
diff --git a/res/drawable/data_sweep_right.xml b/res/drawable/data_sweep_right.xml
index a75a1b2..cbe2a85 100644
--- a/res/drawable/data_sweep_right.xml
+++ b/res/drawable/data_sweep_right.xml
@@ -15,6 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:enterFadeDuration="@android:integer/config_mediumAnimTime"
     android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_right_activated" />
diff --git a/res/drawable/data_sweep_warning.xml b/res/drawable/data_sweep_warning.xml
index 001d0c5..8fbe8e7 100644
--- a/res/drawable/data_sweep_warning.xml
+++ b/res/drawable/data_sweep_warning.xml
@@ -15,6 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:enterFadeDuration="@android:integer/config_mediumAnimTime"
     android:exitFadeDuration="@android:integer/config_mediumAnimTime">
 
     <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_warning_activated" />
diff --git a/res/layout/crypt_keeper_password_entry.xml b/res/layout/crypt_keeper_password_entry.xml
index a5193ce..60dcf6a 100644
--- a/res/layout/crypt_keeper_password_entry.xml
+++ b/res/layout/crypt_keeper_password_entry.xml
@@ -42,4 +42,16 @@
        android:textColor="#ffffffff"
     />
 
-</LinearLayout>
\ No newline at end of file
+   <!-- Emergency call button.
+        Text and icon are set by CryptKeeper.updateEmergencyCallButtonState() -->
+   <Button android:id="@+id/emergencyCallButton"
+       android:layout_width="wrap_content"
+       android:layout_height="wrap_content"
+       android:layout_gravity="left"
+       android:layout_marginTop="10dip"
+       style="@*android:style/Widget.Button.Transparent"
+       android:textSize="14sp"
+       android:drawablePadding="6dip"
+       />
+
+</LinearLayout>
diff --git a/res/layout/data_usage_header.xml b/res/layout/data_usage_header.xml
index 3f4ca5b..547d85d 100644
--- a/res/layout/data_usage_header.xml
+++ b/res/layout/data_usage_header.xml
@@ -19,13 +19,18 @@
     android:layout_height="wrap_content"
     android:orientation="vertical">
 
-    <LinearLayout
-        android:id="@+id/network_switches"
+    <FrameLayout
+        android:id="@+id/network_switches_container"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:showDividers="middle|end"
-        android:divider="?android:attr/listDivider" />
+        android:layout_height="wrap_content">
+        <LinearLayout
+            android:id="@+id/network_switches"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:showDividers="middle|end"
+            android:divider="?android:attr/listDivider" />
+    </FrameLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/res/layout/data_usage_summary.xml b/res/layout/data_usage_summary.xml
index 41b8eed..7e68143 100644
--- a/res/layout/data_usage_summary.xml
+++ b/res/layout/data_usage_summary.xml
@@ -20,6 +20,7 @@
     android:layout_height="match_parent">
 
     <LinearLayout
+        android:id="@+id/tabs_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical">
diff --git a/res/layout/trusted_credential.xml b/res/layout/trusted_credential.xml
new file mode 100644
index 0000000..9955a79
--- /dev/null
+++ b/res/layout/trusted_credential.xml
@@ -0,0 +1,41 @@
+<?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="fill_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize"
+    android:background="?android:attr/selectableItemBackground"
+    android:padding="15dip"
+    >
+    <TextView
+        android:id="@+id/trusted_credential_subject"
+        android:layout_width="0px"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+    />
+    <!-- checkbox is invisible and not gone so that the height is consistent between tabs -->
+    <CheckBox
+        android:id="@+id/trusted_credential_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="invisible"
+        android:clickable="false"
+        android:focusable="false"
+        android:layout_weight="0"
+    />
+</LinearLayout>
diff --git a/res/layout/trusted_credential_details.xml b/res/layout/trusted_credential_details.xml
new file mode 100644
index 0000000..c18d933
--- /dev/null
+++ b/res/layout/trusted_credential_details.xml
@@ -0,0 +1,34 @@
+<?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:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+    <FrameLayout
+        android:id="@+id/cert_details"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        />
+    <Button
+        android:id="@+id/cert_remove_button"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="right"
+        android:layout_margin="6dip"
+        />
+</LinearLayout>
diff --git a/res/layout/trusted_credentials.xml b/res/layout/trusted_credentials.xml
new file mode 100644
index 0000000..06ce44b
--- /dev/null
+++ b/res/layout/trusted_credentials.xml
@@ -0,0 +1,80 @@
+<?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.
+-->
+<TabHost
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="5dp"
+        >
+        <TabWidget
+            android:id="@android:id/tabs"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+         />
+        <FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:padding="5dp"
+            >
+            <FrameLayout
+                android:id="@+id/system_tab"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                >
+                <ProgressBar
+                    android:id="@+id/system_progress"
+                    style="?android:attr/progressBarStyleLarge"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:visibility="gone"
+                />
+                <ListView
+                    android:id="@+id/system_list"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    android:visibility="gone"
+                    >
+                </ListView>
+            </FrameLayout>
+            <FrameLayout
+                android:id="@+id/user_tab"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                >
+                <ProgressBar
+                    android:id="@+id/user_progress"
+                    style="?android:attr/progressBarStyleLarge"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:visibility="gone"
+                />
+                <ListView
+                    android:id="@+id/user_list"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    android:visibility="gone"
+                    >
+                </ListView>
+            </FrameLayout>
+        </FrameLayout>
+    </LinearLayout>
+</TabHost>
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
new file mode 100644
index 0000000..3e4b441
--- /dev/null
+++ b/res/layout/vpn_dialog.xml
@@ -0,0 +1,126 @@
+<?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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+    <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:padding="5mm">
+
+        <LinearLayout android:id="@+id/editor"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+            <TextView style="@style/vpn_label" android:text="@string/vpn_name"/>
+            <EditText style="@style/vpn_value" android:id="@+id/name"
+                    android:singleLine="true"/>
+
+            <TextView style="@style/vpn_label" android:text="@string/vpn_type"/>
+            <Spinner style="@style/vpn_value" android:id="@+id/type"
+                    android:prompt="@string/vpn_type"
+                    android:entries="@array/vpn_types"/>
+
+            <TextView style="@style/vpn_label" android:text="@string/vpn_server"/>
+            <EditText style="@style/vpn_value" android:id="@+id/server"
+                    android:singleLine="true"/>
+
+            <CheckBox style="@style/vpn_value" android:id="@+id/mppe"
+                    android:text="@string/vpn_mppe"
+                    android:visibility="gone"/>
+
+            <LinearLayout android:id="@+id/l2tp"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:visibility="gone">
+                <TextView style="@style/vpn_label" android:text="@string/vpn_l2tp_secret"/>
+                <EditText style="@style/vpn_value" android:id="@+id/l2tp_secret"
+                        android:singleLine="true"
+                        android:password="true"
+                        android:hint="@string/vpn_not_used"/>
+            </LinearLayout>
+
+            <LinearLayout android:id="@+id/ipsec_psk"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:visibility="gone">
+                <TextView style="@style/vpn_label" android:text="@string/vpn_ipsec_identifier"/>
+                <EditText style="@style/vpn_value" android:id="@+id/ipsec_identifier"
+                        android:singleLine="true"
+                        android:hint="@string/vpn_not_used"/>
+
+                <TextView style="@style/vpn_label" android:text="@string/vpn_ipsec_secret"/>
+                <EditText style="@style/vpn_value" android:id="@+id/ipsec_secret"
+                        android:singleLine="true"
+                        android:password="true"/>
+            </LinearLayout>
+
+            <LinearLayout android:id="@+id/ipsec_user"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:visibility="gone">
+                <TextView style="@style/vpn_label" android:text="@string/vpn_ipsec_user_cert"/>
+                <Spinner style="@style/vpn_value" android:id="@+id/ipsec_user_cert"
+                        android:prompt="@string/vpn_ipsec_user_cert" />
+            </LinearLayout>
+
+            <LinearLayout android:id="@+id/ipsec_ca"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:visibility="gone">
+                <TextView style="@style/vpn_label" android:text="@string/vpn_ipsec_ca_cert"/>
+                <Spinner style="@style/vpn_value" android:id="@+id/ipsec_ca_cert"
+                        android:prompt="@string/vpn_ipsec_ca_cert" />
+            </LinearLayout>
+
+            <TextView style="@style/vpn_label" android:text="@string/vpn_domains"/>
+            <EditText style="@style/vpn_value" android:id="@+id/domains"
+                    android:hint="@string/vpn_not_used"/>
+
+            <!-- Not sure if we have time to make it. -->
+            <TextView style="@style/vpn_label" android:text="@string/vpn_routes"
+                    android:visibility="gone"/>
+            <EditText style="@style/vpn_value" android:id="@+id/routes"
+                    android:visibility="gone"/>
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/login"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+            <TextView style="@style/vpn_label" android:text="@string/vpn_username"/>
+            <EditText style="@style/vpn_value" android:id="@+id/username"
+                    android:singleLine="true"/>
+
+            <TextView style="@style/vpn_label" android:text="@string/vpn_password"/>
+            <EditText style="@style/vpn_value" android:id="@+id/password"
+                    android:singleLine="true"
+                    android:password="true"/>
+
+            <CheckBox style="@style/vpn_value" android:id="@+id/save_login"
+                    android:text="@string/vpn_save_login"/>
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 3f2fc23..c0578fa 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -612,5 +612,39 @@
         <item>Use HDCP checking for DRM content only</item>
         <item>Always use HDCP checking</item>
     </string-array>
-</resources>
 
+    <!-- Match this with the constants in VpnProfile. --> <skip />
+    <!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] -->
+    <string-array name="vpn_types" translatable="false">
+        <item>PPTP</item>
+        <item>L2TP/IPSec PSK</item>
+        <item>L2TP/IPSec RSA</item>
+        <item>IPSec Xauth PSK</item>
+        <item>IPSec Xauth RSA</item>
+        <item>IPSec Hybrid RSA</item>
+    </string-array>
+
+    <!-- Match this with the constants in VpnProfile. --> <skip />
+    <!-- Longer descriptions for each VPN type. [CHAR LIMIT=100] -->
+    <string-array name="vpn_types_long">
+        <item>PPTP VPN</item>
+        <item>L2TP/IPSec VPN with pre-shared keys</item>
+        <item>L2TP/IPSec VPN with certificates</item>
+        <item>IPSec VPN with pre-shared keys and Xauth authentication</item>
+        <item>IPSec VPN with certificates and Xauth authentication</item>
+        <item>IPSec VPN with certificates and hybrid authentication</item>
+    </string-array>
+
+    <!-- Match this with the constants in VpnProfile. --> <skip />
+    <!-- Status for a VPN network. [CHAR LIMIT=100] -->
+    <string-array name="vpn_states">
+        <!-- Status message when VPN is connecting. -->
+        <item>Connecting\u2026</item>
+        <!-- Status message when VPN is connected. -->
+        <item>Connected</item>
+        <!-- Status message when VPN is disconnected. -->
+        <item>Disconnected</item>
+        <!-- Status message when VPN failed to connect. -->
+        <item>Failed</item>
+    </string-array>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b0b0a2e..cc677ad 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1082,6 +1082,10 @@
     <string name="wifi_notify_open_networks">Network notification</string>
     <!-- Checkbox summary for option to notify user when open networks are nearby -->
     <string name="wifi_notify_open_networks_summary">Notify me when an open network is available</string>
+    <!-- Checkbox title for option to toggle wifi watchdog service -->
+    <string name="wifi_enable_watchdog_service">Wi-Fi Connectivity Checks</string>
+    <!-- Checkbox summary for option to toggle wifi watchdog service -->
+    <string name="wifi_enable_watchdog_service_summary">Detect and manage potential network connectivity problems</string>
     <!-- Setting title for setting the wifi sleep policy -->
     <string name="wifi_setting_sleep_policy_title">Wi-Fi disconnect policy</string>
     <!-- Setting summary for setting the wifi sleep policy -->
@@ -2611,12 +2615,14 @@
     <string name="accessibility_settings">Accessibility</string>
     <!-- Settings title for accessibility settings screen -->
     <string name="accessibility_settings_title">Accessibility settings</string>
-    <!-- Settings summary for accessibility settings -->
+    <!-- Settings summary for accessibility settings [CHAR LIMIT=40] -->
     <string name="accessibility_settings_summary">Manage accessibility options</string>
-    <!-- Setting Checkbox title for enabling accessibility -->
-    <string name="toggle_accessibility_title">Accessibility</string>
-    <!-- Setting accessibility services category -->
+    <!-- Setting Checkbox title for enabling accessibility large text [CHAR LIMIT=25] -->
+    <string name="toggle_large_text_title">Large text</string>
+    <!-- Setting accessibility services category [CHAR LIMIT=25] -->
     <string name="accessibility_services_category">Accessibility services</string>
+    <!-- Setting Checkbox title for enabling accessibility services [CHAR LIMIT=40] -->
+    <string name="toggle_accessibility_title">Allow accessibility services</string>
     <!-- Message for announcing the lack of installed accessibility services. -->
     <string name="no_accessibility_services_summary">No installed accessibility services.</string>
     <!-- Warning message about security implications of enabling an accessibility service,
@@ -2638,8 +2644,6 @@
         applications installed.\n\nYou can download a screen reader for your device from Android
         Market.\n\nClick "OK" to install the screen reader.</string>
 
-    <!-- Accessibility settings: Webpage accessibility scripts category [CHAR LIMIT=25] -->
-    <string name="accessibility_script_injection_category">Accessibility scripts</string>
     <!-- Accessibility settings: Checkbox title for enabling download of accessibility scripts [CHAR LIMIT=40] -->
     <string name="accessibility_script_injection_enabled">Download accessibility scripts</string>
     <!-- Accessibility settings: Checkbox summary for enabling download of accessibility scripts [CHAR LIMIT=65] -->
@@ -2947,8 +2951,6 @@
 
     <string name="vpn_settings_activity_title">VPN settings</string>
 
-    <!-- Title of VPN connect dialog -->
-    <string name="vpn_connect_to">Connect to <xliff:g id="name" example="Work Network">%s</xliff:g></string>
     <!-- In VPN connect dialog, for inputing username and password -->
     <string name="vpn_username_colon">Username:</string>
     <string name="vpn_password_colon">Password:</string>
@@ -2969,8 +2971,6 @@
     <string name="vpn_menu_revert">Revert</string>
     <string name="vpn_menu_connect">Connect to network</string>
     <string name="vpn_menu_disconnect">Disconnect from network</string>
-    <string name="vpn_menu_edit">Edit network</string>
-    <string name="vpn_menu_delete">Delete network</string>
 
     <!-- VPN error dialog messages -->
     <string name="vpn_error_miss_entering">You must enter <xliff:g id="code">%s</xliff:g>.</string>
@@ -3011,7 +3011,6 @@
     <string name="vpn_connect_hint">Connect to network</string>
 
     <!-- Name of a VPN profile -->
-    <string name="vpn_name">VPN name</string>
     <string name="vpn_a_name">a VPN name</string>
 
     <!-- Toast message shown when a profile is added -->
@@ -3033,7 +3032,6 @@
     <!-- Preference title -->
     <string name="vpn_l2tp_secret_string_title">Set L2TP secret</string>
     <!-- Complete term -->
-    <string name="vpn_l2tp_secret">L2TP secret</string>
     <string name="vpn_a_l2tp_secret">an L2TP secret</string>
     <string name="vpn_pptp_encryption_title">encryption</string>
     <string name="vpn_pptp_encryption">PPTP encryption</string>
@@ -3097,6 +3095,10 @@
     <string name="credentials_reset">Clear credentials</string>
     <!-- Summary of preference to reset credential storage [CHAR LIMIT=NONE] -->
     <string name="credentials_reset_summary">Remove all certificates</string>
+    <!-- Title of preference to display trusted credentials (aka CA certificates) [CHAR LIMIT=30] -->
+    <string name="trusted_credentials">Trusted credentials</string>
+    <!-- Summary of preference to display trusted credentials (aka CA certificates) [CHAR LIMIT=NONE] -->
+    <string name="trusted_credentials_summary">Display trusted CA certificates</string>
 
     <!-- Title of dialog to enable credential storage [CHAR LIMIT=30] -->
     <string name="credentials_unlock">Enter password</string>
@@ -3481,4 +3483,80 @@
     <!-- 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>
 
+    <!-- Button at the bottom of the CryptKeeper screen to make an emergency call. -->
+    <string name="cryptkeeper_emergency_call">Emergency call</string>
+    <!-- Button at the bottom of the CryptKeeper screen that lets the user return to a call -->
+    <string name="cryptkeeper_return_to_call">Return to call</string>
+
+    <!-- Input label for the name of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_name">Name</string>
+    <!-- Input label for the type of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_type">Type</string>
+    <!-- Input label for the server address of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_server">Server address</string>
+    <!-- Checkbox label to enable PPP encryption for a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_mppe">PPP encryption (MPPE)</string>
+    <!-- Input label for the L2TP secret of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_l2tp_secret">L2TP secret</string>
+    <!-- Input label for the IPSec identifier of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_ipsec_identifier">IPSec identifier</string>
+    <!-- Input label for the IPSec pre-shared key of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_ipsec_secret">IPSec pre-shared key</string>
+    <!-- Selection label for the IPSec user certificate of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_ipsec_user_cert">IPSec user certificate</string>
+    <!-- Selection label for the IPSec CA certificate of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_ipsec_ca_cert">IPSec CA certificate</string>
+    <!-- Input label for the DNS search domains of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_domains">DNS search domains</string>
+    <!-- Input label for the forwarding routes of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_routes">Forwarding routes</string>
+    <!-- Input label for the username of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_username">Username</string>
+    <!-- Input label for the password of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_password">Password</string>
+    <!-- Checkbox label to save the username and the password for a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_save_login">Save this information</string>
+
+    <!-- Hint for an optional input of a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_not_used">(not used)</string>
+    <!-- Option to not use a CA certificate to verify the VPN server. [CHAR LIMIT=40] -->
+    <string name="vpn_no_ca_cert">(do not verify server)</string>
+
+    <!-- Button label to cancel chaning a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_cancel">Cancel</string>
+    <!-- Button label to save a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_save">Save</string>
+    <!-- Button label to connect to a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_connect">Connect</string>
+    <!-- Dialog title to edit a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_edit">Edit VPN network</string>
+    <!-- Dialog title to connect to a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_connect_to">Connect to <xliff:g id="network" example="School">%s</xliff:g></string>
+
+    <!-- Preference title for VPN settings. [CHAR LIMIT=40] -->
+    <string name="vpn_title">VPN settings</string>
+    <!-- Preference title to create a new VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_create">Add VPN network</string>
+    <!-- Menu item to edit a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_menu_edit">Edit network</string>
+    <!-- Menu item to delete a VPN network. [CHAR LIMIT=40] -->
+    <string name="vpn_menu_delete">Delete network</string>
+
+    <!-- Tab label for built-in system CA certificates. -->
+    <string name="trusted_credentials_system_tab">System</string>
+    <!-- Tab label for user added CA certificates. -->
+    <string name="trusted_credentials_user_tab">User</string>
+    <!-- Button label for disabling a system CA certificate. -->
+    <string name="trusted_credentials_disable_label">Disable</string>
+    <!-- Button label for enabling a system CA certificate. -->
+    <string name="trusted_credentials_enable_label">Enable</string>
+    <!-- Button label for removing a user CA certificate. -->
+    <string name="trusted_credentials_remove_label">Remove</string>
+    <!-- Alert dialog confirmation when enabling a system CA certificate. -->
+    <string name="trusted_credentials_enable_confirmation">Enable the system CA certificate?</string>
+    <!-- Alert dialog confirmation when disabling a system CA certificate. -->
+    <string name="trusted_credentials_disable_confirmation">Disable the system CA certificate?</string>
+    <!-- Alert dialog confirmation when removing a user CA certificate. -->
+    <string name="trusted_credentials_remove_confirmation">Permanently remove the user CA certificate?</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e2d7fe2..2e3c1d9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -138,4 +138,14 @@
         <item name="android:singleLine">true</item>
     </style>
 
+    <style name="vpn_label">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="vpn_value">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
 </resources>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 771b69e..90aef84 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -19,20 +19,23 @@
         android:title="@string/accessibility_settings_title">
 
     <CheckBoxPreference
-            android:key="toggle_accessibility_service_checkbox"
-            android:title="@string/toggle_accessibility_title"
+            android:key="toggle_large_text_checkbox"
+            android:title="@string/toggle_large_text_title"
             android:persistent="false"/>
 
     <PreferenceCategory android:key="accessibility_services_category"
-            android:title="@string/accessibility_services_category" />
-
-    <PreferenceCategory android:key="accessibility_script_injection_category"
-            android:title="@string/accessibility_script_injection_category">
+            android:title="@string/accessibility_services_category">
+        <CheckBoxPreference
+                android:key="toggle_accessibility_service_checkbox"
+                android:title="@string/toggle_accessibility_title"
+                android:persistent="false"
+                android:order="-10000"/>
         <CheckBoxPreference
                 android:key="toggle_accessibility_script_injection_checkbox"
                 android:title="@string/accessibility_script_injection_enabled"
                 android:summary="@string/accessibility_script_injection_enabled_summary"
-                android:persistent="false" />
+                android:persistent="false"
+                android:order="10000" />
     </PreferenceCategory>
 
     <PreferenceCategory android:key="power_button_category"
diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml
index e996f70..3a88d0b 100644
--- a/res/xml/security_settings_misc.xml
+++ b/res/xml/security_settings_misc.xml
@@ -56,6 +56,11 @@
 
     <PreferenceCategory android:title="@string/credentials_title"
             android:persistent="false">
+        <Preference android:title="@string/trusted_credentials"
+                android:summary="@string/trusted_credentials_summary"
+                android:persistent="false"
+                android:fragment="com.android.settings.TrustedCredentials"/>
+
         <Preference android:title="@string/credentials_install"
                 android:summary="@string/credentials_install_summary"
                 android:persistent="false">
diff --git a/res/xml/vpn_settings2.xml b/res/xml/vpn_settings2.xml
new file mode 100644
index 0000000..189e7ed
--- /dev/null
+++ b/res/xml/vpn_settings2.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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+        android:title="@string/vpn_title">
+    <Preference android:key="add_network"
+            android:title="@string/vpn_create"
+            android:persistent="false"/>
+</PreferenceScreen>
diff --git a/res/xml/wifi_advanced_settings.xml b/res/xml/wifi_advanced_settings.xml
index 1444de1..d7344b1 100644
--- a/res/xml/wifi_advanced_settings.xml
+++ b/res/xml/wifi_advanced_settings.xml
@@ -24,6 +24,13 @@
             android:summary="@string/wifi_notify_open_networks_summary"
             android:persistent="false" />
 
+    <!-- android:dependency="enable_wifi" -->
+    <CheckBoxPreference
+            android:key="wifi_enable_watchdog_service"
+            android:title="@string/wifi_enable_watchdog_service"
+            android:summary="@string/wifi_enable_watchdog_service_summary"
+            android:persistent="false" />
+
     <ListPreference
             android:key="sleep_policy"
             android:title="@string/wifi_setting_sleep_policy_title"
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
index 9a0db5d..bbb3678 100644
--- a/src/com/android/settings/AccessibilitySettings.java
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -17,14 +17,17 @@
 package com.android.settings;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.Service;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
@@ -51,7 +54,12 @@
     private static final String DEFAULT_SCREENREADER_MARKET_LINK =
         "market://search?q=pname:com.google.android.marvin.talkback";
 
-    private final String TOGGLE_ACCESSIBILITY_CHECKBOX =
+    private static final float LARGE_FONT_SCALE = 1.3f;
+
+    private static final String TOGGLE_LARGE_TEXT_CHECKBOX =
+        "toggle_large_text_checkbox";
+
+    private static final String TOGGLE_ACCESSIBILITY_CHECKBOX =
         "toggle_accessibility_service_checkbox";
 
     private static final String ACCESSIBILITY_SERVICES_CATEGORY =
@@ -66,10 +74,10 @@
     private static final String POWER_BUTTON_ENDS_CALL_CHECKBOX =
         "power_button_ends_call";
 
-    private final String KEY_TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
+    private static final String KEY_TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
         "key_toggle_accessibility_service_checkbox";
 
-    private final String KEY_LONG_PRESS_TIMEOUT_LIST_PREFERENCE =
+    private static final String KEY_LONG_PRESS_TIMEOUT_LIST_PREFERENCE =
         "long_press_timeout_list_preference";
 
     private static final int DIALOG_ID_DISABLE_ACCESSIBILITY = 1;
@@ -77,6 +85,7 @@
     private static final int DIALOG_ID_ENABLE_ACCESSIBILITY_SERVICE = 3;
     private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 4;
 
+    private CheckBoxPreference mToggleLargeTextCheckBox;
     private CheckBoxPreference mToggleAccessibilityCheckBox;
     private CheckBoxPreference mToggleScriptInjectionCheckBox;
     private SettingsCheckBoxPreference mToggleAccessibilityServiceCheckBox;
@@ -88,6 +97,8 @@
 
     private ListPreference mLongPressTimeoutListPreference;
 
+    private final Configuration mCurConfig = new Configuration();
+
     private Map<String, AccessibilityServiceInfo> mAccessibilityServices =
         new LinkedHashMap<String, AccessibilityServiceInfo>();
 
@@ -100,6 +111,9 @@
 
         addPreferencesFromResource(R.xml.accessibility_settings);
 
+        mToggleLargeTextCheckBox = (CheckBoxPreference) findPreference(
+                TOGGLE_LARGE_TEXT_CHECKBOX);
+
         mAccessibilityServicesCategory =
             (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_CATEGORY);
 
@@ -145,7 +159,7 @@
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
-        addAccessibilitServicePreferences();
+        addAccessibilityServicePreferences();
 
         final HashSet<String> enabled = new HashSet<String>();
         String settingValue = Settings.Secure.getString(getContentResolver(),
@@ -192,6 +206,8 @@
             showDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
         }
 
+        readFontSizePreference();
+
         super.onActivityCreated(savedInstanceState);
     }
 
@@ -251,10 +267,10 @@
         int count = mAccessibilityServicesCategory.getPreferenceCount();
         for (int i = 0; i < count; i++) {
             Preference pref = mAccessibilityServicesCategory.getPreference(i);
-            pref.setEnabled(isEnabled);
+            if (pref != mToggleAccessibilityCheckBox) {
+                pref.setEnabled(isEnabled);
+            }
         }
-
-        mToggleScriptInjectionCheckBox.setEnabled(isEnabled);
     }
 
     @Override
@@ -263,6 +279,13 @@
 
         if (TOGGLE_ACCESSIBILITY_CHECKBOX.equals(key)) {
             handleEnableAccessibilityStateChange((CheckBoxPreference) preference);
+        } else if (TOGGLE_LARGE_TEXT_CHECKBOX.equals(key)) {
+            try {
+                mCurConfig.fontScale = mToggleLargeTextCheckBox.isChecked()
+                        ? LARGE_FONT_SCALE : 1;
+                ActivityManagerNative.getDefault().updateConfiguration(mCurConfig);
+            } catch (RemoteException e) {
+            }
         } else if (POWER_BUTTON_ENDS_CALL_CHECKBOX.equals(key)) {
             boolean isChecked = ((CheckBoxPreference) preference).isChecked();
             // The checkbox is labeled "Power button ends call"; thus the in-call
@@ -355,20 +378,22 @@
     /**
      * Adds {@link CheckBoxPreference} for enabling or disabling an accessibility services.
      */
-    private void addAccessibilitServicePreferences() {
+    private void addAccessibilityServicePreferences() {
         AccessibilityManager accessibilityManager =
             (AccessibilityManager) getSystemService(Service.ACCESSIBILITY_SERVICE);
 
         List<AccessibilityServiceInfo> installedServices =
             accessibilityManager.getInstalledAccessibilityServiceList();
 
-        if (installedServices.isEmpty()) {
-            getPreferenceScreen().removePreference(mAccessibilityServicesCategory);
-            return;
+        for (int i = 0; i < mAccessibilityServicesCategory.getPreferenceCount(); i++) {
+            Preference pref = mAccessibilityServicesCategory.getPreference(i);
+            if (pref != mToggleAccessibilityCheckBox
+                    && pref != mToggleScriptInjectionCheckBox) {
+                mAccessibilityServicesCategory.removePreference(pref);
+                i--;
+            }
         }
 
-        getPreferenceScreen().addPreference(mAccessibilityServicesCategory);
-
         for (int i = 0, count = installedServices.size(); i < count; ++i) {
             AccessibilityServiceInfo accessibilityServiceInfo = installedServices.get(i);
             String key = accessibilityServiceInfo.getId();
@@ -385,6 +410,7 @@
                 SettingsCheckBoxPreference preference = new SettingsCheckBoxPreference(
                         getActivity(), settingsIntent);
                 preference.setKey(key);
+                preference.setOrder(i);
                 ServiceInfo serviceInfo = accessibilityServiceInfo.getResolveInfo().serviceInfo;
                 preference.setTitle(serviceInfo.loadLabel(getActivity().getPackageManager()));
                 mAccessibilityServicesCategory.addPreference(preference);
@@ -392,6 +418,16 @@
         }
     }
 
+    public void readFontSizePreference() {
+        try {
+            mCurConfig.updateFrom(
+                ActivityManagerNative.getDefault().getConfiguration());
+        } catch (RemoteException e) {
+        }
+        mToggleLargeTextCheckBox.setChecked(Float.compare(mCurConfig.fontScale,
+                LARGE_FONT_SCALE) == 0);
+    }
+
     @Override
     public Dialog onCreateDialog(int dialogId) {
         switch (dialogId) {
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 20bf7ce..612f4c0 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -16,6 +16,7 @@
 
 package com.android.settings;
 
+import com.android.internal.telephony.ITelephony;
 import com.android.internal.widget.PasswordEntryKeyboardHelper;
 import com.android.internal.widget.PasswordEntryKeyboardView;
 
@@ -33,9 +34,11 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.storage.IMountService;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -62,6 +65,9 @@
     private static final int COOL_DOWN_ATTEMPTS = 10;
     private static final int COOL_DOWN_INTERVAL = 30; // 30 seconds
 
+    // Intent action for launching the Emergency Dialer activity.
+    static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
     private int mCooldown;
     PowerManager.WakeLock mWakeLock;
     private EditText mPasswordEntry;
@@ -347,6 +353,8 @@
                     keyboardView, mPasswordEntry, false);
             keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
         }
+
+        updateEmergencyCallButtonState();
     }
 
     private IMountService getMountService() {
@@ -381,4 +389,73 @@
         }
         return false;
     }
-}
\ No newline at end of file
+
+    //
+    // Code to update the state of, and handle clicks from, the "Emergency call" button.
+    //
+    // This code is mostly duplicated from the corresponding code in
+    // LockPatternUtils and LockPatternKeyguardView under frameworks/base.
+    //
+
+    private void updateEmergencyCallButtonState() {
+        Button button = (Button) findViewById(R.id.emergencyCallButton);
+        // The button isn't present at all in some configurations.
+        if (button == null) return;
+
+        if (isEmergencyCallCapable()) {
+            button.setVisibility(View.VISIBLE);
+            button.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        takeEmergencyCallAction();
+                    }
+                });
+        } else {
+            button.setVisibility(View.GONE);
+            return;
+        }
+
+        int newState = TelephonyManager.getDefault().getCallState();
+        int textId;
+        if (newState == TelephonyManager.CALL_STATE_OFFHOOK) {
+            // show "return to call" text and show phone icon
+            textId = R.string.cryptkeeper_return_to_call;
+            int phoneCallIcon = R.drawable.stat_sys_phone_call;
+            button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
+        } else {
+            textId = R.string.cryptkeeper_emergency_call;
+            int emergencyIcon = R.drawable.ic_emergency;
+            button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
+        }
+        button.setText(textId);
+    }
+
+    private boolean isEmergencyCallCapable() {
+        return getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
+    }
+
+    private void takeEmergencyCallAction() {
+        if (TelephonyManager.getDefault().getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) {
+            resumeCall();
+        } else {
+            launchEmergencyDialer();
+        }
+    }
+
+    private void resumeCall() {
+        ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+        if (phone != null) {
+            try {
+                phone.showCallScreen();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling ITelephony service: " + e);
+            }
+        }
+    }
+
+    private void launchEmergencyDialer() {
+        Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        startActivity(intent);
+    }
+}
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index 098f57a..bd79669 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -71,6 +71,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
@@ -136,12 +137,14 @@
     private SharedPreferences mPrefs;
 
     private TabHost mTabHost;
+    private ViewGroup mTabsContainer;
     private TabWidget mTabWidget;
     private ListView mListView;
     private DataUsageAdapter mAdapter;
 
     private ViewGroup mHeader;
 
+    private ViewGroup mNetworkSwitchesContainer;
     private LinearLayout mNetworkSwitches;
     private Switch mDataEnabled;
     private View mDataEnabledView;
@@ -176,6 +179,7 @@
     private NetworkStatsHistory mHistory;
     private NetworkStatsHistory mDetailHistory;
 
+    private String mCurrentTab = null;
     private String mIntentTab = null;
 
     /** Flag used to ignore listeners during binding. */
@@ -209,6 +213,7 @@
         final View view = inflater.inflate(R.layout.data_usage_summary, container, false);
 
         mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
+        mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container);
         mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs);
         mListView = (ListView) view.findViewById(android.R.id.list);
 
@@ -220,6 +225,8 @@
 
         {
             // bind network switches
+            mNetworkSwitchesContainer = (ViewGroup) mHeader.findViewById(
+                    R.id.network_switches_container);
             mNetworkSwitches = (LinearLayout) mHeader.findViewById(R.id.network_switches);
 
             mDataEnabled = new Switch(inflater.getContext());
@@ -263,9 +270,8 @@
             mAppSwitches.addView(mAppRestrictView);
         }
 
-        // TODO: tweak these transitions
-        final LayoutTransition transition = new LayoutTransition();
-        mHeader.setLayoutTransition(transition);
+        // only assign layout transitions once first layout is finished
+        mHeader.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
 
         mAdapter = new DataUsageAdapter();
         mListView.setOnItemClickListener(mListListener);
@@ -345,6 +351,25 @@
     }
 
     /**
+     * Listener to setup {@link LayoutTransition} after first layout pass.
+     */
+    private OnGlobalLayoutListener mFirstLayoutListener = new OnGlobalLayoutListener() {
+        /** {@inheritDoc} */
+        public void onGlobalLayout() {
+            mHeader.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener);
+
+            mTabsContainer.setLayoutTransition(new LayoutTransition());
+            mHeader.setLayoutTransition(new LayoutTransition());
+            mNetworkSwitchesContainer.setLayoutTransition(new LayoutTransition());
+
+            final LayoutTransition chartTransition = new LayoutTransition();
+            chartTransition.setStartDelay(LayoutTransition.APPEARING, 0);
+            chartTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
+            mChart.setLayoutTransition(chartTransition);
+        }
+    };
+
+    /**
      * Rebuild all tabs based on {@link NetworkPolicyEditor} and
      * {@link #mShowWifi}, hiding the tabs entirely when applicable. Selects
      * first tab, and kicks off a full rebind of body contents.
@@ -434,6 +459,9 @@
             throw new IllegalStateException("no mobile or wifi radios");
         }
 
+        final boolean tabChanged = !currentTab.equals(mCurrentTab);
+        mCurrentTab = currentTab;
+
         if (LOGD) Log.d(TAG, "updateBody() with currentTab=" + currentTab);
 
         if (TAB_WIFI.equals(currentTab)) {
@@ -480,7 +508,8 @@
         // bind chart to historical stats
         mChart.bindNetworkStats(mHistory);
 
-        updatePolicy(true);
+        // only update policy when switching tabs
+        updatePolicy(tabChanged);
         updateAppDetail();
 
         // force scroll to top of body
@@ -607,6 +636,12 @@
             // we fall through to update cycle list for detail mode
         } else {
             mNetworkSwitches.setVisibility(View.VISIBLE);
+
+            // when heading back to summary without cycle refresh, kick details
+            // update to repopulate list.
+            if (!refreshCycle) {
+                updateDetailData();
+            }
         }
 
         final NetworkPolicy policy = mPolicyEditor.getPolicy(mTemplate);
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index f7945d8..d76f08f 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -26,15 +26,12 @@
 import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceGroup;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.speech.tts.TextToSpeech;
@@ -695,13 +692,16 @@
         mTts = new TextToSpeech(getActivity().getApplicationContext(), this, engine);
         mEnableDemo = false;
         mVoicesMissing = false;
-        updateWidgetState();
-        checkVoiceData();
 
-        // Finally, persist this value to settings.
+        // Persist this value to settings and update the UI before we check
+        // voice data because if the TTS class connected without any exception, "engine"
+        // will be the default engine irrespective of whether the voice check
+        // passes or not.
         Settings.Secure.putString(getContentResolver(), TTS_DEFAULT_SYNTH, engine);
-        // .. and update the UI.
         mDefaultSynthPref.setValue(engine);
+        updateWidgetState();
+
+        checkVoiceData();
 
         Log.v(TAG, "The default synth is now: " + engine);
     }
diff --git a/src/com/android/settings/TrustedCredentials.java b/src/com/android/settings/TrustedCredentials.java
new file mode 100644
index 0000000..987d2dc
--- /dev/null
+++ b/src/com/android/settings/TrustedCredentials.java
@@ -0,0 +1,390 @@
+/*
+ * 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 android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
+import android.content.DialogInterface;
+import android.net.http.SslCertificate;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.security.IKeyChainService;
+import android.security.KeyChain;
+import android.security.KeyChain.KeyChainConnection;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.FrameLayout;
+import android.widget.ListView;
+import android.widget.TabHost;
+import android.widget.TextView;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.apache.harmony.xnet.provider.jsse.TrustedCertificateStore;
+
+public class TrustedCredentials extends Fragment {
+
+    private static final String TAG = "TrustedCredentials";
+
+    private enum Tab {
+        SYSTEM("system",
+               R.string.trusted_credentials_system_tab,
+               R.id.system_tab,
+               R.id.system_progress,
+               R.id.system_list,
+               true),
+        USER("user",
+             R.string.trusted_credentials_user_tab,
+             R.id.user_tab,
+             R.id.user_progress,
+             R.id.user_list,
+             false);
+
+        private final String mTag;
+        private final int mLabel;
+        private final int mView;
+        private final int mProgress;
+        private final int mList;
+        private final boolean mCheckbox;
+        private Tab(String tag, int label, int view, int progress, int list, boolean checkbox) {
+            mTag = tag;
+            mLabel = label;
+            mView = view;
+            mProgress = progress;
+            mList = list;
+            mCheckbox = checkbox;
+        }
+        private Set<String> getAliases(TrustedCertificateStore store) {
+            switch (this) {
+                case SYSTEM:
+                    return store.allSystemAliases();
+                case USER:
+                    return store.userAliases();
+            }
+            throw new AssertionError();
+        }
+        private boolean deleted(TrustedCertificateStore store, String alias) {
+            switch (this) {
+                case SYSTEM:
+                    return !store.containsAlias(alias);
+                case USER:
+                    return false;
+            }
+            throw new AssertionError();
+        }
+        private int getButtonLabel(CertHolder certHolder) {
+            switch (this) {
+                case SYSTEM:
+                    if (certHolder.mDeleted) {
+                        return R.string.trusted_credentials_enable_label;
+                    }
+                    return R.string.trusted_credentials_disable_label;
+                case USER:
+                    return R.string.trusted_credentials_remove_label;
+            }
+            throw new AssertionError();
+        }
+        private int getButtonConfirmation(CertHolder certHolder) {
+            switch (this) {
+                case SYSTEM:
+                    if (certHolder.mDeleted) {
+                        return R.string.trusted_credentials_enable_confirmation;
+                    }
+                    return R.string.trusted_credentials_disable_confirmation;
+                case USER:
+                    return R.string.trusted_credentials_remove_confirmation;
+            }
+            throw new AssertionError();
+        }
+        private void postOperationUpdate(boolean ok, CertHolder certHolder) {
+            if (ok) {
+                if (certHolder.mTab.mCheckbox) {
+                    certHolder.mDeleted = !certHolder.mDeleted;
+                } else {
+                    certHolder.mAdapter.mCertHolders.remove(certHolder);
+                }
+                certHolder.mAdapter.notifyDataSetChanged();
+            } else {
+                // bail, reload to reset to known state
+                certHolder.mAdapter.load();
+            }
+        }
+    }
+
+    // be careful not to use this on the UI thread since it is does file operations
+    private final TrustedCertificateStore mStore = new TrustedCertificateStore();
+
+    private TabHost mTabHost;
+
+    @Override public View onCreateView(
+            LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+        mTabHost = (TabHost) inflater.inflate(R.layout.trusted_credentials, parent, false);
+        mTabHost.setup();
+        addTab(Tab.SYSTEM);
+        // TODO add Install button on Tab.USER to go to CertInstaller like KeyChainActivity
+        addTab(Tab.USER);
+        return mTabHost;
+    }
+
+    private void addTab(Tab tab) {
+        TabHost.TabSpec systemSpec = mTabHost.newTabSpec(tab.mTag)
+                .setIndicator(getActivity().getString(tab.mLabel))
+                .setContent(tab.mView);
+        mTabHost.addTab(systemSpec);
+
+        ListView lv = (ListView) mTabHost.findViewById(tab.mList);
+        final TrustedCertificateAdapter adapter = new TrustedCertificateAdapter(tab);
+        lv.setAdapter(adapter);
+        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
+                showCertDialog(adapter.getItem(pos));
+            }
+        });
+    }
+
+    private class TrustedCertificateAdapter extends BaseAdapter {
+        private final List<CertHolder> mCertHolders = new ArrayList<CertHolder>();
+        private final Tab mTab;
+        private TrustedCertificateAdapter(Tab tab) {
+            mTab = tab;
+            load();
+        }
+        private void load() {
+            new AliasLoader().execute();
+        }
+        @Override public int getCount() {
+            return mCertHolders.size();
+        }
+        @Override public CertHolder getItem(int position) {
+            return mCertHolders.get(position);
+        }
+        @Override public long getItemId(int position) {
+            return position;
+        }
+        @Override public View getView(int position, View view, ViewGroup parent) {
+            ViewHolder holder;
+            if (view == null) {
+                LayoutInflater inflater = LayoutInflater.from(getActivity());
+                view = inflater.inflate(R.layout.trusted_credential, parent, false);
+                holder = new ViewHolder();
+                holder.mSubjectView = (TextView)view.findViewById(R.id.trusted_credential_subject);
+                holder.mCheckBox = (CheckBox) view.findViewById(R.id.trusted_credential_status);
+                view.setTag(holder);
+            } else {
+                holder = (ViewHolder) view.getTag();
+            }
+            CertHolder certHolder = mCertHolders.get(position);
+            holder.mSubjectView.setText(certHolder.mSubject);
+            if (mTab.mCheckbox) {
+                holder.mCheckBox.setChecked(!certHolder.mDeleted);
+                holder.mCheckBox.setVisibility(View.VISIBLE);
+            }
+            return view;
+        };
+
+        private class AliasLoader extends AsyncTask<Void, Void, List<CertHolder>> {
+            @Override protected void onPreExecute() {
+                View content = mTabHost.getTabContentView();
+                content.findViewById(mTab.mProgress).setVisibility(View.VISIBLE);
+                content.findViewById(mTab.mList).setVisibility(View.GONE);
+            }
+            @Override protected List<CertHolder> doInBackground(Void... params) {
+                Set<String> aliases = mTab.getAliases(mStore);
+                List<CertHolder> certHolders = new ArrayList<CertHolder>(aliases.size());
+                for (String alias : aliases) {
+                    X509Certificate cert = (X509Certificate) mStore.getCertificate(alias, true);
+                    certHolders.add(new CertHolder(mStore,
+                                                   TrustedCertificateAdapter.this,
+                                                   mTab,
+                                                   alias,
+                                                   cert));
+                }
+                Collections.sort(certHolders);
+                return certHolders;
+            }
+            @Override protected void onPostExecute(List<CertHolder> certHolders) {
+                mCertHolders.clear();
+                mCertHolders.addAll(certHolders);
+                notifyDataSetChanged();
+                View content = mTabHost.getTabContentView();
+                content.findViewById(mTab.mProgress).setVisibility(View.GONE);
+                content.findViewById(mTab.mList).setVisibility(View.VISIBLE);
+            }
+        }
+    }
+
+    private static class CertHolder implements Comparable<CertHolder> {
+        private final TrustedCertificateStore mStore;
+        private final TrustedCertificateAdapter mAdapter;
+        private final Tab mTab;
+        private final String mAlias;
+        private final X509Certificate mX509Cert;
+
+        private final SslCertificate mSslCert;
+        private final String mSubject;
+        private boolean mDeleted;
+
+        private CertHolder(TrustedCertificateStore store,
+                           TrustedCertificateAdapter adapter,
+                           Tab tab,
+                           String alias,
+                           X509Certificate x509Cert) {
+            mStore = store;
+            mAdapter = adapter;
+            mTab = tab;
+            mAlias = alias;
+            mX509Cert = x509Cert;
+
+            mSslCert = new SslCertificate(x509Cert);
+
+            String cn = mSslCert.getIssuedTo().getCName();
+            String o = mSslCert.getIssuedTo().getOName();
+            String ou = mSslCert.getIssuedTo().getUName();
+            StringBuilder sb = new StringBuilder();
+            if (!cn.isEmpty()) {
+                sb.append("CN=" + cn);
+            }
+            if (!o.isEmpty()) {
+                if (sb.length() != 0) {
+                    sb.append(", ");
+                }
+                sb.append("O=" + o);
+            }
+            if (!ou.isEmpty()) {
+                if (sb.length() != 0) {
+                    sb.append(", ");
+                }
+                sb.append("OU=" + ou);
+            }
+            if (sb.length() != 0) {
+                mSubject = sb.toString();
+            } else {
+                mSubject = mSslCert.getIssuedTo().getDName();
+            }
+
+            mDeleted = mTab.deleted(mStore, mAlias);
+        }
+        @Override public int compareTo(CertHolder o) {
+            return this.mSubject.compareTo(o.mSubject);
+        }
+        @Override public boolean equals(Object o) {
+            if (!(o instanceof CertHolder)) {
+                return false;
+            }
+            CertHolder other = (CertHolder) o;
+            return mAlias.equals(other.mAlias);
+        }
+        @Override public int hashCode() {
+            return mAlias.hashCode();
+        }
+    }
+
+    private static class ViewHolder {
+        private TextView mSubjectView;
+        private CheckBox mCheckBox;
+    }
+
+    private void showCertDialog(final CertHolder certHolder) {
+        View view = View.inflate(getActivity(), R.layout.trusted_credential_details, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(com.android.internal.R.string.ssl_certificate);
+        builder.setView(view);
+        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+            @Override public void onClick(DialogInterface dialog, int id) {
+                dialog.dismiss();
+            }
+        });
+        final Dialog certDialog = builder.create();
+
+        FrameLayout details = (FrameLayout) view.findViewById(R.id.cert_details);
+        details.addView(certHolder.mSslCert.inflateCertificateView(getActivity()));
+
+        Button removeButton = (Button) view.findViewById(R.id.cert_remove_button);
+        removeButton.setText(certHolder.mTab.getButtonLabel(certHolder));
+        removeButton.setOnClickListener(new View.OnClickListener() {
+            @Override public void onClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setMessage(certHolder.mTab.getButtonConfirmation(certHolder));
+                builder.setPositiveButton(
+                        android.R.string.yes, new DialogInterface.OnClickListener() {
+                    @Override public void onClick(DialogInterface dialog, int id) {
+                        new AliasOperation(certHolder).execute();
+                        dialog.dismiss();
+                        certDialog.dismiss();
+                    }
+                });
+                builder.setNegativeButton(
+                        android.R.string.no, new DialogInterface.OnClickListener() {
+                    @Override public void onClick(DialogInterface dialog, int id) {
+                        dialog.cancel();
+                    }
+                });
+                AlertDialog alert = builder.create();
+                alert.show();
+            }
+        });
+
+        certDialog.show();
+    }
+
+    private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
+        private final CertHolder mCertHolder;
+        private AliasOperation(CertHolder certHolder) {
+            mCertHolder = certHolder;
+        }
+        @Override protected Boolean doInBackground(Void... params) {
+            try {
+                KeyChainConnection keyChainConnection = KeyChain.bind(getActivity());
+                IKeyChainService service = keyChainConnection.getService();
+                try {
+                    if (mCertHolder.mDeleted) {
+                        byte[] bytes = mCertHolder.mX509Cert.getEncoded();
+                        service.installCaCertificate(bytes);
+                        return true;
+                    } else {
+                        return service.deleteCaCertificate(mCertHolder.mAlias);
+                    }
+                } finally {
+                    keyChainConnection.close();
+                }
+            } catch (CertificateEncodingException e) {
+                return false;
+            } catch (IllegalStateException e) {
+                // used by installCaCertificate to report errors
+                return false;
+            } catch (RemoteException e) {
+                return false;
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return false;
+            }
+        }
+        @Override protected void onPostExecute(Boolean ok) {
+            mCertHolder.mTab.postOperationUpdate(ok, mCertHolder);
+        }
+    }
+}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index caf7aef..1c02f74 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -282,7 +282,7 @@
                         intent.setPackage(mAppEntry.info.packageName);
                         List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
                         if ((homes != null && homes.size() > 0) ||
-                                (mPackageInfo != null &&
+                                (mPackageInfo != null && mPackageInfo.signatures != null &&
                                         sys.signatures[0].equals(mPackageInfo.signatures[0]))) {
                             // Disable button for core system applications.
                             mUninstallButton.setText(R.string.disable_text);
@@ -482,8 +482,10 @@
         ActivityManager am = (ActivityManager)
                 getActivity().getSystemService(Context.ACTIVITY_SERVICE);
         int compatMode = am.getPackageScreenCompatMode(packageName);
-        if (compatMode == ActivityManager.COMPAT_MODE_DISABLED
-                || compatMode == ActivityManager.COMPAT_MODE_ENABLED) {
+        // For now these are always off; this is the old UI model which we
+        // are no longer using.
+        if (false && (compatMode == ActivityManager.COMPAT_MODE_DISABLED
+                || compatMode == ActivityManager.COMPAT_MODE_ENABLED)) {
             mScreenCompatSection.setVisibility(View.VISIBLE);
             mAskCompatibilityCB.setChecked(am.getPackageAskScreenCompat(packageName));
             mAskCompatibilityCB.setOnCheckedChangeListener(this);
diff --git a/src/com/android/settings/vpn2/VpnDialog.java b/src/com/android/settings/vpn2/VpnDialog.java
new file mode 100644
index 0000000..b3e417b
--- /dev/null
+++ b/src/com/android/settings/vpn2/VpnDialog.java
@@ -0,0 +1,325 @@
+/*
+ * 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.vpn2;
+
+import com.android.settings.R;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListener {
+    private static final String DUMMY = "\r\r\r\r";
+
+    private static String getDummy(String secret) {
+        return secret.isEmpty() ? "" : DUMMY;
+    }
+
+    private static String getSecret(TextView dummy) {
+        String secret = dummy.getText().toString();
+        return DUMMY.equals(secret) ? "" : secret;
+    }
+
+    private final KeyStore mKeyStore = KeyStore.getInstance();
+    private final DialogInterface.OnClickListener mListener;
+    private final VpnProfile mProfile;
+
+    private boolean mEditing;
+
+    private View mView;
+
+    private TextView mName;
+    private Spinner mType;
+    private TextView mServer;
+    private TextView mUsername;
+    private TextView mPassword;
+    private TextView mDomains;
+    private TextView mRoutes;
+    private CheckBox mMppe;
+    private TextView mL2tpSecret;
+    private TextView mIpsecIdentifier;
+    private TextView mIpsecSecret;
+    private Spinner mIpsecUserCert;
+    private Spinner mIpsecCaCert;
+    private CheckBox mSaveLogin;
+
+    VpnDialog(Context context, DialogInterface.OnClickListener listener,
+            VpnProfile profile, boolean editing) {
+        super(context);
+        mListener = listener;
+        mProfile = profile;
+        mEditing = editing;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedState) {
+        mView = getLayoutInflater().inflate(R.layout.vpn_dialog, null);
+        setView(mView);
+        setInverseBackgroundForced(true);
+
+        Context context = getContext();
+
+        // First, find out all the fields.
+        mName = (TextView) mView.findViewById(R.id.name);
+        mType = (Spinner) mView.findViewById(R.id.type);
+        mServer = (TextView) mView.findViewById(R.id.server);
+        mUsername = (TextView) mView.findViewById(R.id.username);
+        mPassword = (TextView) mView.findViewById(R.id.password);
+        mDomains = (TextView) mView.findViewById(R.id.domains);
+        mRoutes = (TextView) mView.findViewById(R.id.routes);
+        mMppe = (CheckBox) mView.findViewById(R.id.mppe);
+        mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret);
+        mIpsecIdentifier = (TextView) mView.findViewById(R.id.ipsec_identifier);
+        mIpsecSecret = (TextView) mView.findViewById(R.id.ipsec_secret);
+        mIpsecUserCert = (Spinner) mView.findViewById(R.id.ipsec_user_cert);
+        mIpsecCaCert = (Spinner) mView.findViewById(R.id.ipsec_ca_cert);
+        mSaveLogin = (CheckBox) mView.findViewById(R.id.save_login);
+
+        // Second, copy values from the profile.
+        mName.setText(mProfile.name);
+        mType.setSelection(mProfile.type);
+        mServer.setText(mProfile.server);
+        mUsername.setText(mProfile.username);
+        mPassword.setText(getDummy(mProfile.password));
+        mDomains.setText(mProfile.domains);
+        mRoutes.setText(mProfile.routes);
+        mMppe.setChecked(mProfile.mppe);
+        mL2tpSecret.setText(getDummy(mProfile.l2tpSecret));
+        mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
+        mIpsecSecret.setText(getDummy(mProfile.ipsecSecret));
+        loadCertificates(mIpsecUserCert, Credentials.USER_CERTIFICATE,
+                0, mProfile.ipsecUserCert);
+        loadCertificates(mIpsecUserCert, Credentials.CA_CERTIFICATE,
+                R.string.vpn_no_ca_cert, mProfile.ipsecCaCert);
+        mSaveLogin.setChecked(mProfile.saveLogin);
+
+        // Third, add listeners to required fields.
+        mName.addTextChangedListener(this);
+        mType.setOnItemSelectedListener(this);
+        mServer.addTextChangedListener(this);
+        mUsername.addTextChangedListener(this);
+        mPassword.addTextChangedListener(this);
+        mIpsecSecret.addTextChangedListener(this);
+        mIpsecUserCert.setOnItemSelectedListener(this);
+
+        // Forth, determine to do editing or connecting.
+        boolean valid = validate(true);
+        mEditing = mEditing || !valid;
+
+        if (mEditing) {
+            setTitle(R.string.vpn_edit);
+
+            // Show common fields.
+            mView.findViewById(R.id.editor).setVisibility(View.VISIBLE);
+
+            // Show type-specific fields.
+            changeType(mProfile.type);
+
+            // Create a button to save the profile.
+            setButton(DialogInterface.BUTTON_POSITIVE,
+                    context.getString(R.string.vpn_save), mListener);
+        } else {
+            setTitle(context.getString(R.string.vpn_connect_to, mProfile.name));
+
+            // Not editing, just show username and password.
+            mView.findViewById(R.id.login).setVisibility(View.VISIBLE);
+
+            // Create a button to connect the network.
+            setButton(DialogInterface.BUTTON_POSITIVE,
+                    context.getString(R.string.vpn_connect), mListener);
+        }
+
+        // Always provide a cancel button.
+        setButton(DialogInterface.BUTTON_NEGATIVE,
+                context.getString(R.string.vpn_cancel), mListener);
+
+        // Let AlertDialog create everything.
+        super.onCreate(null);
+
+        // Disable the action button if necessary.
+        getButton(DialogInterface.BUTTON_POSITIVE)
+                .setEnabled(mEditing ? valid : validate(false));
+    }
+
+    @Override
+    public void afterTextChanged(Editable field) {
+        getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+    }
+
+    @Override
+    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+        if (parent == mType) {
+            changeType(position);
+        }
+        getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(false));
+    }
+
+    @Override
+    public void onNothingSelected(AdapterView<?> parent) {
+    }
+
+    private void changeType(int type) {
+        // First, hide everything.
+        mMppe.setVisibility(View.GONE);
+        mView.findViewById(R.id.l2tp).setVisibility(View.GONE);
+        mView.findViewById(R.id.ipsec_psk).setVisibility(View.GONE);
+        mView.findViewById(R.id.ipsec_user).setVisibility(View.GONE);
+        mView.findViewById(R.id.ipsec_ca).setVisibility(View.GONE);
+
+        // Then, unhide type-specific fields.
+        switch (type) {
+            case VpnProfile.TYPE_PPTP:
+                mMppe.setVisibility(View.VISIBLE);
+                break;
+
+            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+                mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE);
+                // fall through
+            case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+                mView.findViewById(R.id.ipsec_psk).setVisibility(View.VISIBLE);
+                break;
+
+            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+                mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE);
+                // fall through
+            case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+                mView.findViewById(R.id.ipsec_ca).setVisibility(View.VISIBLE);
+                // fall through
+            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+                mView.findViewById(R.id.ipsec_user).setVisibility(View.VISIBLE);
+                break;
+        }
+    }
+
+    private boolean validate(boolean editing) {
+        if (!editing) {
+            return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
+        }
+        if (mName.getText().length() == 0 || mServer.getText().length() == 0) {
+            return false;
+        }
+        switch (mType.getSelectedItemPosition()) {
+            case VpnProfile.TYPE_PPTP:
+                return true;
+
+            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+            case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+                return mIpsecSecret.getText().length() != 0;
+
+            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+            case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+                return mIpsecUserCert.getSelectedItemPosition() != 0;
+        }
+        return false;
+    }
+
+    private void loadCertificates(Spinner spinner, String prefix, int firstId, String selected) {
+        Context context = getContext();
+        String first = (firstId == 0) ? "" : context.getString(firstId);
+        String[] certs = mKeyStore.saw(prefix);
+
+        if (certs == null || certs.length == 0) {
+            certs = new String[] {first};
+        } else {
+            String[] array = new String[certs.length + 1];
+            array[0] = first;
+            System.arraycopy(certs, 0, array, 1, certs.length);
+            certs = array;
+        }
+
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
+                context, android.R.layout.simple_spinner_item, certs);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spinner.setAdapter(adapter);
+
+        for (int i = 1; i < certs.length; ++i) {
+            if (certs[i].equals(selected)) {
+                spinner.setSelection(i);
+                break;
+            }
+        }
+    }
+
+    boolean isEditing() {
+        return mEditing;
+    }
+
+    VpnProfile getProfile() {
+        // First, save common fields.
+        VpnProfile profile = new VpnProfile(mProfile.key);
+        profile.name = mName.getText().toString();
+        profile.type = mType.getSelectedItemPosition();
+        profile.server = mServer.getText().toString().trim();
+        profile.username = mUsername.getText().toString();
+        profile.password = getSecret(mPassword);
+        profile.domains = mDomains.getText().toString().trim();
+        profile.routes = mRoutes.getText().toString().trim();
+
+        // Then, save type-specific fields.
+        switch (profile.type) {
+            case VpnProfile.TYPE_PPTP:
+                profile.mppe = mMppe.isChecked();
+                break;
+
+            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+                profile.l2tpSecret = getSecret(mL2tpSecret);
+                // fall through
+            case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+                profile.ipsecSecret = getSecret(mIpsecSecret);
+                break;
+
+            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+                profile.l2tpSecret = getSecret(mL2tpSecret);
+                // fall through
+            case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+                if (mIpsecCaCert.getSelectedItemPosition() != 0) {
+                    profile.ipsecCaCert = (String) mIpsecCaCert.getSelectedItem();
+                }
+                // fall through
+            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+                if (mIpsecUserCert.getSelectedItemPosition() != 0) {
+                    profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem();
+                }
+                break;
+        }
+
+        profile.saveLogin = mSaveLogin.isChecked();
+        return profile;
+    }
+}
diff --git a/src/com/android/settings/vpn2/VpnProfile.java b/src/com/android/settings/vpn2/VpnProfile.java
new file mode 100644
index 0000000..9e4c528
--- /dev/null
+++ b/src/com/android/settings/vpn2/VpnProfile.java
@@ -0,0 +1,115 @@
+/*
+ * 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.vpn2;
+
+import java.nio.charset.Charsets;
+
+/**
+ * Parcel-like entity class for VPN profiles. To keep things simple, all
+ * fields are package private. Methods are provided for serialization, so
+ * storage can be implemented easily. Two rules are set for this class.
+ * First, all fields must be kept non-null. Second, always make a copy
+ * using clone() before modifying.
+ */
+class VpnProfile implements Cloneable {
+    // Match these constants with R.array.vpn_types.
+    static final int TYPE_PPTP = 0;
+    static final int TYPE_L2TP_IPSEC_PSK = 1;
+    static final int TYPE_L2TP_IPSEC_RSA = 2;
+    static final int TYPE_IPSEC_XAUTH_PSK = 3;
+    static final int TYPE_IPSEC_XAUTH_RSA = 4;
+    static final int TYPE_IPSEC_HYBRID_RSA = 5;
+    static final int TYPE_MAX = 5;
+
+    // Entity fields.
+    final String key;           // -1
+    String name = "";           // 0
+    int type = TYPE_PPTP;       // 1
+    String server = "";         // 2
+    String username = "";       // 3
+    String password = "";       // 4
+    String domains = "";        // 5
+    String routes = "";         // 6
+    boolean mppe = false;       // 7
+    String l2tpSecret = "";     // 8
+    String ipsecIdentifier = "";// 9
+    String ipsecSecret = "";    // 10
+    String ipsecUserCert = "";  // 11
+    String ipsecCaCert = "";    // 12
+
+    // Helper fields.
+    boolean saveLogin = false;
+
+    VpnProfile(String key) {
+        this.key = key;
+    }
+
+    static VpnProfile decode(String key, byte[] value) {
+        try {
+            if (key == null) {
+                return null;
+            }
+
+            String[] values = new String(value, Charsets.UTF_8).split("\0", -1);
+            // Currently it always has 13 fields.
+            if (values.length < 13) {
+                return null;
+            }
+
+            VpnProfile profile = new VpnProfile(key);
+            profile.name = values[0];
+            profile.type = Integer.valueOf(values[1]);
+            if (profile.type < 0 || profile.type > TYPE_MAX) {
+                return null;
+            }
+            profile.server = values[2];
+            profile.username = values[3];
+            profile.password = values[4];
+            profile.domains = values[5];
+            profile.routes = values[6];
+            profile.mppe = Boolean.valueOf(values[7]);
+            profile.l2tpSecret = values[8];
+            profile.ipsecIdentifier = values[9];
+            profile.ipsecSecret = values[10];
+            profile.ipsecUserCert = values[11];
+            profile.ipsecCaCert = values[12];
+
+            profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
+            return profile;
+        } catch (Exception e) {
+            // ignore
+        }
+        return null;
+    }
+
+    byte[] encode() {
+        StringBuilder builder = new StringBuilder(name);
+        builder.append('\0').append(type);
+        builder.append('\0').append(server);
+        builder.append('\0').append(saveLogin ? username : "");
+        builder.append('\0').append(saveLogin ? password : "");
+        builder.append('\0').append(domains);
+        builder.append('\0').append(routes);
+        builder.append('\0').append(mppe);
+        builder.append('\0').append(l2tpSecret);
+        builder.append('\0').append(ipsecIdentifier);
+        builder.append('\0').append(ipsecSecret);
+        builder.append('\0').append(ipsecUserCert);
+        builder.append('\0').append(ipsecCaCert);
+        return builder.toString().getBytes(Charsets.UTF_8);
+    }
+}
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
new file mode 100644
index 0000000..6662dd9
--- /dev/null
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -0,0 +1,347 @@
+/*
+ * 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.vpn2;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.preference.PreferenceGroup;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+import com.android.settings.SettingsPreferenceFragment;
+
+import java.util.HashMap;
+
+public class VpnSettings extends SettingsPreferenceFragment implements
+        Handler.Callback, Preference.OnPreferenceClickListener,
+        DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+
+    private static final String TAG = "VpnSettings";
+
+    // Match these constants with R.array.vpn_states.
+    private static final int STATE_NONE = -1;
+    private static final int STATE_CONNECTING = 0;
+    private static final int STATE_CONNECTED = 1;
+    private static final int STATE_DISCONNECTED = 2;
+    private static final int STATE_FAILED = 3;
+
+    private final KeyStore mKeyStore = KeyStore.getInstance();
+    private boolean mUnlocking = false;
+
+    private HashMap<String, VpnPreference> mPreferences;
+    private VpnDialog mDialog;
+    private String mSelectedKey;
+    private Handler mHandler;
+
+    @Override
+    public void onCreate(Bundle savedState) {
+        super.onCreate(savedState);
+        addPreferencesFromResource(R.xml.vpn_settings2);
+        PreferenceGroup group = getPreferenceScreen();
+        group.setOrderingAsAdded(false);
+        group.findPreference("add_network").setOnPreferenceClickListener(this);
+
+        if (savedState != null) {
+            VpnProfile profile = VpnProfile.decode(savedState.getString("VpnKey"),
+                    savedState.getByteArray("VpnProfile"));
+            if (profile != null) {
+                mDialog = new VpnDialog(getActivity(), this, profile,
+                        savedState.getBoolean("VpnEditing"));
+            }
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle savedState) {
+        // We do not save view hierarchy, as they are just profiles.
+        if (mDialog != null) {
+            VpnProfile profile = mDialog.getProfile();
+            savedState.putString("VpnKey", profile.key);
+            savedState.putByteArray("VpnProfile", profile.encode());
+            savedState.putBoolean("VpnEditing", mDialog.isEditing());
+        }
+        // else?
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        // Check KeyStore here, so others do not need to deal with it.
+        if (mKeyStore.state() != KeyStore.State.UNLOCKED) {
+            if (!mUnlocking) {
+                // Let us unlock KeyStore. See you later!
+                Credentials.getInstance().unlock(getActivity());
+            } else {
+                // We already tried, but it is still not working!
+                getActivity().getFragmentManager().popBackStack();
+            }
+            mUnlocking = !mUnlocking;
+            return;
+        }
+
+        // Now KeyStore is always unlocked. Reset the flag.
+        mUnlocking = false;
+
+        // Currently we are the only user of profiles in KeyStore.
+        // Assuming KeyStore and KeyGuard do the right thing, we can
+        // safely cache profiles in the memory.
+        if (mPreferences == null) {
+            mPreferences = new HashMap<String, VpnPreference>();
+
+            String[] keys = mKeyStore.saw(Credentials.VPN);
+            if (keys != null && keys.length > 0) {
+                Context context = getActivity();
+
+                for (String key : keys) {
+                    VpnProfile profile = VpnProfile.decode(key,
+                            mKeyStore.get(Credentials.VPN + key));
+                    if (profile == null) {
+                        Log.w(TAG, "bad profile: key = " + key);
+                        mKeyStore.delete(Credentials.VPN + key);
+                    } else {
+                        VpnPreference preference = new VpnPreference(context, profile);
+                        mPreferences.put(key, preference);
+                    }
+                }
+            }
+        }
+        PreferenceGroup group = getPreferenceScreen();
+        for (VpnPreference preference : mPreferences.values()) {
+            group.addPreference(preference);
+        }
+
+        // Show the dialog if there is one.
+        if (mDialog != null) {
+            mDialog.setOnDismissListener(this);
+            mDialog.show();
+        }
+
+        // Start monitoring.
+        if (mHandler == null) {
+            mHandler = new Handler(this);
+        }
+        mHandler.sendEmptyMessage(0);
+
+        // Register for context menu. Hmmm, getListView() is hidden?
+        registerForContextMenu(getListView());
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        // Hide the dialog if there is one.
+        if (mDialog != null) {
+            mDialog.setOnDismissListener(null);
+            mDialog.dismiss();
+        }
+
+        // Unregister for context menu.
+        unregisterForContextMenu(getListView());
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        // Here is the exit of a dialog.
+        mDialog = null;
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int button) {
+        if (button == DialogInterface.BUTTON_POSITIVE) {
+            // Always save the profile.
+            VpnProfile profile = mDialog.getProfile();
+            mKeyStore.put(Credentials.VPN + profile.key, profile.encode());
+
+            // Update the preference.
+            VpnPreference preference = mPreferences.get(profile.key);
+            if (preference != null) {
+                disconnect(profile.key);
+                preference.update(profile);
+            } else {
+                preference = new VpnPreference(getActivity(), profile);
+                mPreferences.put(profile.key, preference);
+                getPreferenceScreen().addPreference(preference);
+            }
+
+            // If we are not editing, connect!
+            if (!mDialog.isEditing()) {
+                connect(profile.key);
+            }
+        }
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
+        if (mDialog != null) {
+            Log.v(TAG, "onCreateContextMenu() is called when mDialog != null");
+            return;
+        }
+
+        if (info instanceof AdapterContextMenuInfo) {
+            Preference preference = (Preference) getListView().getItemAtPosition(
+                    ((AdapterContextMenuInfo) info).position);
+            if (preference instanceof VpnPreference) {
+                VpnProfile profile = ((VpnPreference) preference).getProfile();
+                mSelectedKey = profile.key;
+                menu.setHeaderTitle(profile.name);
+                menu.add(Menu.NONE, R.string.vpn_menu_edit, 0, R.string.vpn_menu_edit);
+                menu.add(Menu.NONE, R.string.vpn_menu_delete, 0, R.string.vpn_menu_delete);
+            }
+        }
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        if (mDialog != null) {
+            Log.v(TAG, "onContextItemSelected() is called when mDialog != null");
+            return false;
+        }
+
+        VpnPreference preference = mPreferences.get(mSelectedKey);
+        if (preference == null) {
+            Log.v(TAG, "onContextItemSelected() is called but no preference is found");
+            return false;
+        }
+
+        switch (item.getItemId()) {
+            case R.string.vpn_menu_edit:
+                mDialog = new VpnDialog(getActivity(), this, preference.getProfile(), true);
+                mDialog.setOnDismissListener(this);
+                mDialog.show();
+                return true;
+            case R.string.vpn_menu_delete:
+                disconnect(mSelectedKey);
+                getPreferenceScreen().removePreference(preference);
+                mPreferences.remove(mSelectedKey);
+                mKeyStore.delete(Credentials.VPN + mSelectedKey);
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (mDialog != null) {
+            Log.v(TAG, "onPreferenceClick() is called when mDialog != null");
+            return true;
+        }
+
+        if (preference instanceof VpnPreference) {
+            mDialog = new VpnDialog(getActivity(), this,
+                    ((VpnPreference) preference).getProfile(), false);
+        } else {
+            // Generate a new key. Here we just use the current time.
+            long millis = System.currentTimeMillis();
+            while (mPreferences.containsKey(Long.toHexString(millis))) {
+                ++millis;
+            }
+            mDialog = new VpnDialog(getActivity(), this,
+                    new VpnProfile(Long.toHexString(millis)), true);
+        }
+        mDialog.setOnDismissListener(this);
+        mDialog.show();
+        return true;
+    }
+
+    @Override
+    public boolean handleMessage(Message message) {
+        mHandler.removeMessages(0);
+
+        if (isResumed()) {
+
+
+
+
+            mHandler.sendEmptyMessageDelayed(0, 1000);
+        }
+        return true;
+    }
+
+    private void connect(String key) {
+    }
+
+    private void disconnect(String key) {
+    }
+
+
+    private class VpnPreference extends Preference {
+        private VpnProfile mProfile;
+        private int mState = STATE_NONE;
+
+        VpnPreference(Context context, VpnProfile profile) {
+            super(context);
+            setPersistent(false);
+            setOnPreferenceClickListener(VpnSettings.this);
+
+            mProfile = profile;
+            update();
+        }
+
+        VpnProfile getProfile() {
+            return mProfile;
+        }
+
+        void update(VpnProfile profile) {
+            mProfile = profile;
+            update();
+        }
+
+        void update() {
+            if (mState != STATE_NONE) {
+                String[] states = getContext().getResources()
+                        .getStringArray(R.array.vpn_states);
+                setSummary(states[mState]);
+            } else {
+                String[] types = getContext().getResources()
+                        .getStringArray(R.array.vpn_types_long);
+                setSummary(types[mProfile.type]);
+            }
+            setTitle(mProfile.name);
+            notifyChanged();
+        }
+
+        @Override
+        public int compareTo(Preference preference) {
+            int result = 1;
+            if (preference instanceof VpnPreference) {
+                VpnPreference another = (VpnPreference) preference;
+
+                if ((result = another.mState - mState) == 0 &&
+                        (result = mProfile.name.compareTo(another.mProfile.name)) == 0 &&
+                        (result = mProfile.type - another.mProfile.type) == 0) {
+                    result = mProfile.key.compareTo(another.mProfile.key);
+                }
+            }
+            return result;
+        }
+    }
+}
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index d8344d5..6c9ded4 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -188,7 +188,12 @@
     }
 
     public float getPoint() {
-        return mAxis.convertToPoint(mValue);
+        if (isEnabled()) {
+            return mAxis.convertToPoint(mValue);
+        } else {
+            // when disabled, show along top edge
+            return 0;
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java
index bf5616d..9223ca6 100644
--- a/src/com/android/settings/widget/ChartView.java
+++ b/src/com/android/settings/widget/ChartView.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -93,7 +94,6 @@
                 // sweep is always placed along specific dimension
                 final ChartSweepView sweep = (ChartSweepView) child;
                 final Rect sweepMargins = sweep.getSweepMargins();
-                final float point = sweep.getPoint();
 
                 if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) {
                     parentRect.left = parentRect.right =
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java
index 6fe4042..a8bdaa6 100644
--- a/src/com/android/settings/widget/DataUsageChartView.java
+++ b/src/com/android/settings/widget/DataUsageChartView.java
@@ -129,9 +129,7 @@
             mSweepLimit.setValue(policy.limitBytes);
             mSweepLimit.setEnabled(true);
         } else {
-            // TODO: set limit default based on axis maximum
             mSweepLimit.setVisibility(View.VISIBLE);
-            mSweepLimit.setValue(5 * GB_IN_BYTES);
             mSweepLimit.setEnabled(false);
         }
 
@@ -189,6 +187,15 @@
         }
     }
 
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (!isActivated()) {
+            return true;
+        } else {
+            return super.onInterceptTouchEvent(ev);
+        }
+    }
+
     /**
      * Return current inspection range (start and end time) based on internal
      * {@link ChartSweepView} positions.
@@ -302,56 +309,45 @@
     public static class DataAxis implements ChartAxis {
         private long mMin;
         private long mMax;
-        private long mMinLog;
-        private long mMaxLog;
         private float mSize;
 
         public DataAxis() {
             // TODO: adapt ranges to show when history >5GB, and handle 4G
             // interfaces with higher limits.
-            setBounds(1 * MB_IN_BYTES, 5 * GB_IN_BYTES);
+            setBounds(0, 5 * GB_IN_BYTES);
         }
 
         /** {@inheritDoc} */
         public void setBounds(long min, long max) {
             mMin = min;
             mMax = max;
-            mMinLog = (long) Math.log(mMin);
-            mMaxLog = (long) Math.log(mMax);
         }
 
         /** {@inheritDoc} */
         public void setSize(float size) {
-            this.mSize = size;
+            mSize = size;
         }
 
         /** {@inheritDoc} */
         public float convertToPoint(long value) {
-            return (mSize * (value - mMin)) / (mMax - mMin);
-
-            // TODO: finish tweaking log scale
-//            if (value > mMin) {
-//                return (float) ((mSize * (Math.log(value) - mMinLog)) / (mMaxLog - mMinLog));
-//            } else {
-//                return 0;
-//            }
+            // TODO: this assumes range of [0,5]GB
+            final double fraction = Math.pow(
+                    10, 0.36884343106175160321 * Math.log10(value) + -3.62828151137812282556);
+            return (float) fraction * mSize;
         }
 
         /** {@inheritDoc} */
         public long convertToValue(float point) {
-            return (long) (mMin + ((point * (mMax - mMin)) / mSize));
-
-            // TODO: finish tweaking log scale
-//            return (long) Math.pow(Math.E, (mMinLog + ((point * (mMaxLog - mMinLog)) / mSize)));
+            final double y = point / mSize;
+            // TODO: this assumes range of [0,5]GB
+            final double fraction = 6.869341163271789302 * Math.pow(10, 9)
+                    * Math.pow(y, 2.71117746931646030774);
+            return (long) fraction;
         }
 
         /** {@inheritDoc} */
         public CharSequence getLabel(long value) {
-
             // TODO: use exploded string here
-
-
-            // TODO: convert to string
             return Long.toString(value);
         }
 
@@ -365,13 +361,13 @@
         public float[] getTickPoints() {
             final float[] tickPoints = new float[16];
 
-            long value = mMax;
-            float mult = 0.8f;
+            final long jump = ((mMax - mMin) / tickPoints.length);
+            long value = mMin;
             for (int i = 0; i < tickPoints.length; i++) {
                 tickPoints[i] = convertToPoint(value);
-                value = (long) (value * mult);
-                mult *= 0.9;
+                value += jump;
             }
+
             return tickPoints;
         }
     }
diff --git a/src/com/android/settings/wifi/AdvancedSettings.java b/src/com/android/settings/wifi/AdvancedSettings.java
index 4855c99..cd7b8a3 100644
--- a/src/com/android/settings/wifi/AdvancedSettings.java
+++ b/src/com/android/settings/wifi/AdvancedSettings.java
@@ -43,6 +43,7 @@
     private static final String KEY_FREQUENCY_BAND = "frequency_band";
     private static final String KEY_NOTIFY_OPEN_NETWORKS = "notify_open_networks";
     private static final String KEY_SLEEP_POLICY = "sleep_policy";
+    private static final String KEY_ENABLE_WIFI_WATCHDOG = "wifi_enable_watchdog_service";
 
     private WifiManager mWifiManager;
 
@@ -72,6 +73,13 @@
                 Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
         notifyOpenNetworks.setEnabled(mWifiManager.isWifiEnabled());
 
+        CheckBoxPreference watchdogEnabled =
+                (CheckBoxPreference) findPreference(KEY_ENABLE_WIFI_WATCHDOG);
+        watchdogEnabled.setChecked(Secure.getInt(getContentResolver(),
+                Secure.WIFI_WATCHDOG_ON, 1) == 1);
+
+        watchdogEnabled.setEnabled(mWifiManager.isWifiEnabled());
+
         ListPreference frequencyPref = (ListPreference) findPreference(KEY_FREQUENCY_BAND);
 
         if (mWifiManager.isDualBandSupported()) {
@@ -111,12 +119,17 @@
             Secure.putInt(getContentResolver(),
                     Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                     ((CheckBoxPreference) preference).isChecked() ? 1 : 0);
+        } else if (KEY_ENABLE_WIFI_WATCHDOG.equals(key)) {
+            Secure.putInt(getContentResolver(),
+                    Secure.WIFI_WATCHDOG_ON,
+                    ((CheckBoxPreference) preference).isChecked() ? 1 : 0);
         } else {
             return super.onPreferenceTreeClick(screen, preference);
         }
         return true;
     }
 
+    @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         String key = preference.getKey();
 
diff --git a/src/com/android/settings/wifi/AdvancedWifiSettings.java b/src/com/android/settings/wifi/AdvancedWifiSettings.java
index 1da8b68..bc92b3a 100644
--- a/src/com/android/settings/wifi/AdvancedWifiSettings.java
+++ b/src/com/android/settings/wifi/AdvancedWifiSettings.java
@@ -76,6 +76,7 @@
         }
     }
 
+    @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         String key = preference.getKey();
         if (key == null) return true;