Merge change 4127 into donut

* changes:
  Make the SD Card settings use the system file size formatter.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2714457..03978cc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -115,9 +115,8 @@
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.net.vpn.SETTINGS" />
-                <action android:name="android.net.vpn.INSTALL_PROFILE" />
-                <category android:name="android.intent.category.LAUNCHER" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE_LAUNCH" />
             </intent-filter>
         </activity>
 
@@ -190,6 +189,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="com.android.settings.SOUND_SETTINGS" />
                 <action android:name="com.android.settings.DISPLAY_SETTINGS" />
+                <action android:name="android.settings.DISPLAY_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
             </intent-filter>
diff --git a/res/drawable/app_gauge.9.png b/res/drawable/app_gauge.9.png
index f8ff669..f6c7c99 100644
--- a/res/drawable/app_gauge.9.png
+++ b/res/drawable/app_gauge.9.png
Binary files differ
diff --git a/res/drawable/widget_btn_bluetooth.png b/res/drawable/widget_btn_bluetooth.png
index 5de9d78..f32d0b2 100644
--- a/res/drawable/widget_btn_bluetooth.png
+++ b/res/drawable/widget_btn_bluetooth.png
Binary files differ
diff --git a/res/drawable/widget_btn_bluetooth_gray.png b/res/drawable/widget_btn_bluetooth_gray.png
index 843dcce..a633554 100644
--- a/res/drawable/widget_btn_bluetooth_gray.png
+++ b/res/drawable/widget_btn_bluetooth_gray.png
Binary files differ
diff --git a/res/drawable/widget_btn_bluetooth_off.png b/res/drawable/widget_btn_bluetooth_off.png
index b831a46..c0ef641 100644
--- a/res/drawable/widget_btn_bluetooth_off.png
+++ b/res/drawable/widget_btn_bluetooth_off.png
Binary files differ
diff --git a/res/drawable/widget_btn_brightness.png b/res/drawable/widget_btn_brightness.png
index a162899..9a7c7b9 100644
--- a/res/drawable/widget_btn_brightness.png
+++ b/res/drawable/widget_btn_brightness.png
Binary files differ
diff --git a/res/drawable/widget_btn_brightness_off.png b/res/drawable/widget_btn_brightness_off.png
index 0f42f2d..46dc508 100644
--- a/res/drawable/widget_btn_brightness_off.png
+++ b/res/drawable/widget_btn_brightness_off.png
Binary files differ
diff --git a/res/drawable/widget_btn_gps.png b/res/drawable/widget_btn_gps.png
index 3394cb4..b21e8c8 100644
--- a/res/drawable/widget_btn_gps.png
+++ b/res/drawable/widget_btn_gps.png
Binary files differ
diff --git a/res/drawable/widget_btn_gps_off.png b/res/drawable/widget_btn_gps_off.png
index 7f481d8..042fefb 100644
--- a/res/drawable/widget_btn_gps_off.png
+++ b/res/drawable/widget_btn_gps_off.png
Binary files differ
diff --git a/res/drawable/widget_btn_sync.png b/res/drawable/widget_btn_sync.png
index 9682879..6133233 100644
--- a/res/drawable/widget_btn_sync.png
+++ b/res/drawable/widget_btn_sync.png
Binary files differ
diff --git a/res/drawable/widget_btn_sync_off.png b/res/drawable/widget_btn_sync_off.png
index 0f48a1d..192cad8 100644
--- a/res/drawable/widget_btn_sync_off.png
+++ b/res/drawable/widget_btn_sync_off.png
Binary files differ
diff --git a/res/drawable/widget_btn_wifi.png b/res/drawable/widget_btn_wifi.png
index ff7d2ef..2d39681 100644
--- a/res/drawable/widget_btn_wifi.png
+++ b/res/drawable/widget_btn_wifi.png
Binary files differ
diff --git a/res/drawable/widget_btn_wifi_gray.png b/res/drawable/widget_btn_wifi_gray.png
index 8a3cc49..76f36e8 100644
--- a/res/drawable/widget_btn_wifi_gray.png
+++ b/res/drawable/widget_btn_wifi_gray.png
Binary files differ
diff --git a/res/drawable/widget_btn_wifi_off.png b/res/drawable/widget_btn_wifi_off.png
index 8f15b4f..9b70cf1 100644
--- a/res/drawable/widget_btn_wifi_off.png
+++ b/res/drawable/widget_btn_wifi_off.png
Binary files differ
diff --git a/res/layout/power_usage_detail_item_text.xml b/res/layout/power_usage_detail_item_text.xml
index 097469b..7ea2432 100644
--- a/res/layout/power_usage_detail_item_text.xml
+++ b/res/layout/power_usage_detail_item_text.xml
@@ -27,8 +27,9 @@
         android:textStyle="bold"
         android:singleLine="true"
         android:layout_alignParentLeft="true"
-        android:layout_marginBottom="2dip"
-        android:layout_marginTop="2dip" />
+        android:layout_marginBottom="4dip"
+        android:layout_marginTop="4dip"
+        android:layout_marginLeft="4dip" />
     <TextView
         android:id="@+id/value"
         android:layout_width="wrap_content"
@@ -37,7 +38,7 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textStyle="normal"
         android:singleLine="true"
-        android:layout_marginBottom="2dip"
-        android:layout_marginTop="2dip"
-        android:layout_marginRight="4dip"/>
+        android:layout_marginBottom="4dip"
+        android:layout_marginTop="4dip"
+        android:layout_marginRight="10dip"/>
 </RelativeLayout>
diff --git a/res/layout/power_usage_details.xml b/res/layout/power_usage_details.xml
index 206eb05..8aa625f 100644
--- a/res/layout/power_usage_details.xml
+++ b/res/layout/power_usage_details.xml
@@ -96,6 +96,7 @@
             <TextView
                 android:id="@+id/controls_section_title"
                 style="?android:attr/listSeparatorTextViewStyle"
+                android:layout_marginTop="6dip"
                 android:text="@string/controls_subtitle" />
             
             <RelativeLayout
@@ -130,6 +131,7 @@
         <TextView
             android:id="@+id/packages_section_title"
             style="?android:attr/listSeparatorTextViewStyle"
+            android:layout_marginTop="6dip"
             android:text="@string/packages_subtitle" />
 
         <LinearLayout
diff --git a/res/layout/widget.xml b/res/layout/widget.xml
index c409e68..dea290e 100644
--- a/res/layout/widget.xml
+++ b/res/layout/widget.xml
@@ -36,25 +36,13 @@
         />
 
         <ImageButton
-            android:id="@+id/btn_brightness"
+            android:id="@+id/btn_bluetooth"
             android:layout_width="wrap_content"
             android:layout_height="fill_parent"
             android:layout_marginLeft="3dip"
             android:layout_marginRight="3dip"
             android:background="@drawable/widget_btn"
             android:layout_gravity="center_horizontal"
-
-        />
-
-        <ImageButton
-            android:id="@+id/btn_sync"
-            android:layout_width="wrap_content"
-            android:layout_height="fill_parent"
-            android:layout_marginLeft="3dip"
-            android:layout_marginRight="3dip"
-            android:background="@drawable/widget_btn"
-            android:layout_gravity="center_horizontal"
-
         />
 
         <ImageButton
@@ -65,17 +53,26 @@
             android:layout_marginRight="3dip"
             android:background="@drawable/widget_btn"
             android:layout_gravity="center_horizontal"
-
         />
 
-            <ImageButton
-            android:id="@+id/btn_bluetooth"
+        <ImageButton
+            android:id="@+id/btn_sync"
             android:layout_width="wrap_content"
             android:layout_height="fill_parent"
             android:layout_marginLeft="3dip"
             android:layout_marginRight="3dip"
             android:background="@drawable/widget_btn"
             android:layout_gravity="center_horizontal"
-
         />
+
+        <ImageButton
+            android:id="@+id/btn_brightness"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="3dip"
+            android:layout_marginRight="3dip"
+            android:background="@drawable/widget_btn"
+            android:layout_gravity="center_horizontal"
+        />
+
     </LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d2ca51b..c6c3a2c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1532,16 +1532,16 @@
     <string name="battery_history_starts">Starts: <xliff:g id="starts">%1$d</xliff:g></string>
 
     <!-- Used to show an amount of time in the form "d days, h hours, m minutes, s seconds" in BatteryHistory -->
-    <string name="battery_history_days"><xliff:g id="days">%1$d</xliff:g> d, <xliff:g id="hours">%2$d</xliff:g> h, <xliff:g id="minutes">%3$d</xliff:g> m, <xliff:g id="seconds">%4$d</xliff:g> s</string>
+    <string name="battery_history_days"><xliff:g id="days">%1$d</xliff:g>d <xliff:g id="hours">%2$d</xliff:g>h <xliff:g id="minutes">%3$d</xliff:g>m <xliff:g id="seconds">%4$d</xliff:g>s</string>
 
     <!-- Used to show an amount of time in the form "h hours, m minutes, s seconds" in BatteryHistory -->
-    <string name="battery_history_hours"><xliff:g id="hours">%1$d</xliff:g> h, <xliff:g id="minutes">%2$d</xliff:g> m, <xliff:g id="seconds">%3$d</xliff:g> s</string>
+    <string name="battery_history_hours"><xliff:g id="hours">%1$d</xliff:g>h <xliff:g id="minutes">%2$d</xliff:g>m <xliff:g id="seconds">%3$d</xliff:g>s</string>
 
     <!-- Used to show an amount of time in the form "m minutes, s seconds" in BatteryHistory -->
-    <string name="battery_history_minutes"><xliff:g id="minutes">%1$d</xliff:g> m, <xliff:g id="seconds">%2$d</xliff:g> s</string>
+    <string name="battery_history_minutes"><xliff:g id="minutes">%1$d</xliff:g>m <xliff:g id="seconds">%2$d</xliff:g>s</string>
 
     <!-- Used to show an amount of time in the form "s seconds" in BatteryHistory -->
-    <string name="battery_history_seconds"><xliff:g id="seconds">%1$d</xliff:g> s</string>
+    <string name="battery_history_seconds"><xliff:g id="seconds">%1$d</xliff:g>s</string>
 
     <!-- Used to head a list of packages that share a given user id BatteryHistory -->
     <string name="battery_history_packages_sharing_this_uid">Packages sharing this UID:</string>
@@ -1634,6 +1634,8 @@
     <string name="battery_since_unplugged">Battery usage since unplugged</string>
     <!-- Battery usage since user reset the stats -->
     <string name="battery_since_reset">Battery usage since reset</string>
+    <!-- Battery usage duration -->
+    <string name="battery_stats_duration">Usage duration - <xliff:g id="time">%1$s</xliff:g></string>
     <!-- CPU awake time title -->
     <string name="awake">Device awake time</string>
     <!-- Wifi on time -->
@@ -1798,5 +1800,5 @@
 
     <string name="vpn_settings_category">VPN</string>
     <string name="vpn_settings_title">VPN</string>
-    <string name="vpn_settings_summary">Set up and manage VPN configurations, connections</string>
+    <string name="vpn_settings_summary">Set up &amp; manage VPN configurations, connections</string>
 </resources>
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 80342a8..450e438 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -16,5 +16,6 @@
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
         android:title="@string/battery_since_unplugged">
-
+    <PreferenceCategory
+        android:key="app_list"/>
 </PreferenceScreen>
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index cb37465..ccf360a 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -163,12 +163,12 @@
         
         PreferenceScreen vpnPreferences = getPreferenceManager()
                 .createPreferenceScreen(this);
-        vpnPreferences.setTitle(R.string.vpn_settings_category);
+        vpnPreferences.setTitle(R.string.vpn_settings_title);
+        vpnPreferences.setSummary(R.string.vpn_settings_summary);
         vpnPreferences.setIntent(new VpnManager(this).createSettingsActivityIntent());
 
         PreferenceCategory vpnCat = new PreferenceCategory(this);
-        vpnCat.setTitle(R.string.vpn_settings_title);
-        vpnCat.setSummary(R.string.vpn_settings_summary);
+        vpnCat.setTitle(R.string.vpn_settings_category);
         root.addPreference(vpnCat);
         vpnCat.addPreference(vpnPreferences);
 
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index 54a0b88..e36a8bc 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -51,8 +51,8 @@
     public static final int ACTION_DISPLAY_SETTINGS = 1;
     public static final int ACTION_WIFI_SETTINGS = 2;
     public static final int ACTION_BLUETOOTH_SETTINGS = 3;
-    public static final int ACTION_FORCE_STOP = 4;
-    public static final int ACTION_UNINSTALL = 5;
+    public static final int ACTION_WIRELESS_SETTINGS = 4;
+    public static final int ACTION_APP_DETAILS = 6;
 
     public static final int USAGE_SINCE_UNPLUGGED = 1;
     public static final int USAGE_SINCE_RESET = 2;
@@ -66,10 +66,6 @@
     public static final String EXTRA_DETAIL_VALUES = "values";
     public static final String EXTRA_DRAIN_TYPE = "drainType";
 
-    private static final int SECONDS_PER_MINUTE = 60;
-    private static final int SECONDS_PER_HOUR = 60 * 60;
-    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
-
     private static final boolean DEBUG = true;
     private String mTitle;
     private double mPercentage;
@@ -135,10 +131,10 @@
                 switch (mTypes[i]) {
                     case R.string.usage_type_data_recv:
                     case R.string.usage_type_data_send:
-                        value = formatBytes(mValues[i]);
+                        value = Utils.formatBytes(this, mValues[i]);
                         break;
                     default:
-                        value = formatTime(mValues[i]);
+                        value = Utils.formatElapsedTime(this, mValues[i]);
                 }
                 ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
                         null);
@@ -165,15 +161,12 @@
                 startActivity(new Intent(Settings.ACTION_DISPLAY_SETTINGS));
                 break;
             case ACTION_WIFI_SETTINGS:
-                startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
+                startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
                 break;
             case ACTION_BLUETOOTH_SETTINGS:
-                startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+                startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
                 break;
-            case ACTION_FORCE_STOP:
-                killProcesses();
-                break;
-            case ACTION_UNINSTALL:
+            case ACTION_APP_DETAILS:
                 Intent intent = new Intent(Intent.ACTION_VIEW);
                 intent.setClass(this, InstalledAppDetails.class);
                 intent.putExtra("com.android.settings.ApplicationPkgName", mPackages[0]);
@@ -199,18 +192,17 @@
         if (uid == 0 || !isSystem) { 
             switch (mDrainType) {
                 case APP:
-                    label1 = getString(R.string.battery_action_stop);
+                    //label1 = getString(R.string.battery_action_stop);
                     label2 = getString(R.string.battery_action_app_details);
-                    mAction1 = ACTION_FORCE_STOP;
-                    mAction2 = ACTION_UNINSTALL;
+                    mAction2 = ACTION_APP_DETAILS;
                     break;
                 case SCREEN:
-                    //label2 = getString(R.string.battery_action_display);
-                    //mAction2 = ACTION_DISPLAY_SETTINGS;
+                    label2 = getString(R.string.battery_action_display);
+                    mAction2 = ACTION_DISPLAY_SETTINGS;
                     break;
                 case WIFI:
                     label2 = getString(R.string.battery_action_wifi);
-                    mAction2 = ACTION_WIFI_SETTINGS;
+                    mAction2 = ACTION_WIRELESS_SETTINGS;
                     break;
                 case BLUETOOTH:
                     //label2 = getString(R.string.battery_action_bluetooth);
@@ -291,44 +283,4 @@
             }
         }
     }
-
-    private String formatTime(double millis) {
-        StringBuilder sb = new StringBuilder();
-        int seconds = (int) Math.floor(millis / 1000);
-
-        int days = 0, hours = 0, minutes = 0;
-        if (seconds > SECONDS_PER_DAY) {
-            days = seconds / SECONDS_PER_DAY;
-            seconds -= days * SECONDS_PER_DAY;
-        }
-        if (seconds > SECONDS_PER_HOUR) {
-            hours = seconds / SECONDS_PER_HOUR;
-            seconds -= hours * SECONDS_PER_HOUR;
-        }
-        if (seconds > SECONDS_PER_MINUTE) {
-            minutes = seconds / SECONDS_PER_MINUTE;
-            seconds -= minutes * SECONDS_PER_MINUTE;
-        }
-        if (days > 0) {
-            sb.append(getString(R.string.battery_history_days, days, hours, minutes, seconds));
-        } else if (hours > 0) {
-            sb.append(getString(R.string.battery_history_hours, hours, minutes, seconds));
-        } else if (minutes > 0) {
-            sb.append(getString(R.string.battery_history_minutes, minutes, seconds));
-        } else {
-            sb.append(getString(R.string.battery_history_seconds, seconds));
-        }
-        return sb.toString();
-    }
-
-    private String formatBytes(double bytes) {
-        // TODO: I18N
-        if (bytes > 1000 * 1000) {
-            return String.format("%.2f MB", ((int) (bytes / 1000)) / 1000f);
-        } else if (bytes > 1024) {
-            return String.format("%.2f KB", ((int) (bytes / 10)) / 100f);
-        } else {
-            return String.format("%d bytes", (int) bytes);
-        }
-    }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 10ede87..b8919ee 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -100,7 +100,7 @@
         addPreferencesFromResource(R.xml.power_usage_summary);
         mBatteryInfo = IBatteryStats.Stub.asInterface(
                 ServiceManager.getService("batteryinfo"));
-        mAppListGroup = getPreferenceScreen();
+        mAppListGroup = (PreferenceGroup) findPreference("app_list");
         mPowerProfile = new PowerProfile(this);
     }
 
@@ -108,7 +108,7 @@
     protected void onResume() {
         super.onResume();
         mAbort = false;
-        updateAppsList();
+        refreshStats();
     }
 
     @Override
@@ -207,18 +207,18 @@
                 } else {
                     mStatsType = BatteryStats.STATS_TOTAL;
                 }
-                updateAppsList();
+                refreshStats();
                 return true;
             case MENU_STATS_REFRESH:
                 mStats = null;
-                updateAppsList();
+                refreshStats();
                 return true;
             default:
                 return false;
         }
     }
 
-    private void updateAppsList() {
+    private void refreshStats() {
         if (mStats == null) {
             load();
         }
@@ -263,12 +263,19 @@
         }
     }
 
+    private void updateStatsPeriod(long duration) {
+        String durationString = Utils.formatElapsedTime(this, duration / 1000);
+        String label = getString(R.string.battery_stats_duration, durationString);
+        mAppListGroup.setTitle(label);
+    }
+
     private void processAppUsage() {
         SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
         final int which = mStatsType;
         final double powerCpuNormal = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_NORMAL);
         final double averageCostPerByte = getAverageDataCost();
-        long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime(), which) * 1000;
+        long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
+        updateStatsPeriod(uSecTime);
         SparseArray<? extends Uid> uidStats = mStats.getUidStats();
         final int NU = uidStats.size();
         for (int iu = 0; iu < NU; iu++) {
diff --git a/src/com/android/settings/fuelgauge/Utils.java b/src/com/android/settings/fuelgauge/Utils.java
new file mode 100644
index 0000000..2ffc9de
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/Utils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 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.fuelgauge;
+
+import android.content.Context;
+
+import com.android.settings.R;
+
+/**
+ * Contains utility functions for formatting elapsed time and consumed bytes
+ */
+public class Utils {
+    private static final int SECONDS_PER_MINUTE = 60;
+    private static final int SECONDS_PER_HOUR = 60 * 60;
+    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
+    /**
+     * Returns elapsed time for the given millis, in the following format:
+     * 2d 5h 40m 29s
+     * @param context the application context
+     * @param millis the elapsed time in milli seconds
+     * @return the formatted elapsed time
+     */
+    public static String formatElapsedTime(Context context, double millis) {
+        StringBuilder sb = new StringBuilder();
+        int seconds = (int) Math.floor(millis / 1000);
+
+        int days = 0, hours = 0, minutes = 0;
+        if (seconds > SECONDS_PER_DAY) {
+            days = seconds / SECONDS_PER_DAY;
+            seconds -= days * SECONDS_PER_DAY;
+        }
+        if (seconds > SECONDS_PER_HOUR) {
+            hours = seconds / SECONDS_PER_HOUR;
+            seconds -= hours * SECONDS_PER_HOUR;
+        }
+        if (seconds > SECONDS_PER_MINUTE) {
+            minutes = seconds / SECONDS_PER_MINUTE;
+            seconds -= minutes * SECONDS_PER_MINUTE;
+        }
+        if (days > 0) {
+            sb.append(context.getString(R.string.battery_history_days,
+                    days, hours, minutes, seconds));
+        } else if (hours > 0) {
+            sb.append(context.getString(R.string.battery_history_hours, hours, minutes, seconds));
+        } else if (minutes > 0) {
+            sb.append(context.getString(R.string.battery_history_minutes, minutes, seconds));
+        } else {
+            sb.append(context.getString(R.string.battery_history_seconds, seconds));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Formats data size in KB, MB, from the given bytes.
+     * @param context the application context
+     * @param bytes data size in bytes
+     * @return the formatted size such as 4.52 MB or 245 KB or 332 bytes
+     */
+    public static String formatBytes(Context context, double bytes) {
+        // TODO: I18N
+        if (bytes > 1000 * 1000) {
+            return String.format("%.2f MB", ((int) (bytes / 1000)) / 1000f);
+        } else if (bytes > 1024) {
+            return String.format("%.2f KB", ((int) (bytes / 10)) / 100f);
+        } else {
+            return String.format("%d bytes", (int) bytes);
+        }
+    }
+}
diff --git a/src/com/android/settings/vpn/L2tpIpsecEditor.java b/src/com/android/settings/vpn/L2tpIpsecEditor.java
index 2bb4c8d..2dee92e 100644
--- a/src/com/android/settings/vpn/L2tpIpsecEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecEditor.java
@@ -29,7 +29,7 @@
 /**
  * The class for editing {@link L2tpIpsecProfile}.
  */
-class L2tpIpsecEditor extends SingleServerEditor {
+class L2tpIpsecEditor extends VpnProfileEditor {
     private static final String TAG = L2tpIpsecEditor.class.getSimpleName();
 
     private ListPreference mUserCertificate;
@@ -43,23 +43,19 @@
         mProfile = p;
     }
 
-    //@Override
-    public void loadPreferencesTo(PreferenceGroup subsettings) {
-        super.loadPreferencesTo(subsettings);
-        Context c = subsettings.getContext();
-        subsettings.addPreference(createUserkeyPreference(c));
-        subsettings.addPreference(createUserCertificatePreference(c));
-        subsettings.addPreference(createCaCertificatePreference(c));
-        subsettings.addPreference(createDomainSufficesPreference(c));
+    @Override
+    protected void loadExtraPreferencesTo(PreferenceGroup subpanel) {
+        Context c = subpanel.getContext();
+        subpanel.addPreference(createUserkeyPreference(c));
+        subpanel.addPreference(createUserCertificatePreference(c));
+        subpanel.addPreference(createCaCertificatePreference(c));
     }
 
-    //@Override
+    @Override
     public String validate(Context c) {
         String result = super.validate(c);
         if (result != null) {
             return result;
-        } else if (mProfile.isCustomized()) {
-            return null;
         } else if (Util.isNullOrEmpty(mUserkey.getValue())) {
             return c.getString(R.string.vpn_error_userkey_not_selected);
         } else if (Util.isNullOrEmpty(mUserCertificate.getValue())) {
diff --git a/src/com/android/settings/vpn/SingleServerEditor.java b/src/com/android/settings/vpn/SingleServerEditor.java
deleted file mode 100644
index 63964b4..0000000
--- a/src/com/android/settings/vpn/SingleServerEditor.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2007 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.vpn;
-
-import com.android.settings.R;
-
-import android.content.Context;
-import android.net.vpn.SingleServerProfile;
-import android.net.vpn.VpnProfile;
-import android.preference.EditTextPreference;
-import android.preference.Preference;
-import android.preference.PreferenceGroup;
-
-/**
- * The class for editing {@link SingleServerProfile}.
- */
-class SingleServerEditor implements VpnProfileEditor {
-    private EditTextPreference mServerName;
-    private EditTextPreference mDomainSuffices;
-    private SingleServerProfile mProfile;
-
-    public SingleServerEditor(SingleServerProfile p) {
-        mProfile = p;
-    }
-
-    //@Override
-    public VpnProfile getProfile() {
-        return mProfile;
-    }
-
-    //@Override
-    public void loadPreferencesTo(PreferenceGroup subpanel) {
-        Context c = subpanel.getContext();
-        subpanel.addPreference(createServerNamePreference(c));
-    }
-
-    //@Override
-    public String validate(Context c) {
-        return (mProfile.isCustomized()
-                ? null
-                : (Util.isNullOrEmpty(mServerName.getText())
-                        ? c.getString(R.string.vpn_error_server_name_empty)
-                        : null));
-    }
-
-    /**
-     * Creates a preference for users to input domain suffices.
-     */
-    protected EditTextPreference createDomainSufficesPreference(Context c) {
-        EditTextPreference pref = mDomainSuffices = new EditTextPreference(c);
-        pref.setTitle(R.string.vpn_dns_search_list_title);
-        pref.setDialogTitle(R.string.vpn_dns_search_list_title);
-        pref.setPersistent(true);
-        pref.setText(mProfile.getDomainSuffices());
-        pref.setSummary(mProfile.getDomainSuffices());
-        pref.setOnPreferenceChangeListener(
-                new Preference.OnPreferenceChangeListener() {
-                    public boolean onPreferenceChange(
-                            Preference pref, Object newValue) {
-                        String v = ((String) newValue).trim();
-                        mProfile.setDomainSuffices(v);
-                        pref.setSummary(checkNull(v, pref.getContext()));
-                        return true;
-                    }
-                });
-        return pref;
-    }
-
-    private Preference createServerNamePreference(Context c) {
-        EditTextPreference serverName = mServerName = new EditTextPreference(c);
-        String title = c.getString(R.string.vpn_server_name_title);
-        serverName.setTitle(title);
-        serverName.setDialogTitle(title);
-        serverName.setSummary(checkNull(mProfile.getServerName(), c));
-        serverName.setText(mProfile.getServerName());
-        serverName.setPersistent(true);
-        serverName.setOnPreferenceChangeListener(
-                new Preference.OnPreferenceChangeListener() {
-                    public boolean onPreferenceChange(
-                            Preference pref, Object newValue) {
-                        String v = ((String) newValue).trim();
-                        mProfile.setServerName(v);
-                        pref.setSummary(checkNull(v, pref.getContext()));
-                        return true;
-                    }
-                });
-        return mServerName;
-    }
-
-
-   String checkNull(String value, Context c) {
-        return ((value != null && value.length() > 0)
-                ? value
-                : c.getString(R.string.vpn_not_set));
-   }
-}
diff --git a/src/com/android/settings/vpn/VpnEditor.java b/src/com/android/settings/vpn/VpnEditor.java
index a37b335..35c8bfb 100644
--- a/src/com/android/settings/vpn/VpnEditor.java
+++ b/src/com/android/settings/vpn/VpnEditor.java
@@ -22,7 +22,6 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.vpn.L2tpIpsecProfile;
-import android.net.vpn.SingleServerProfile;
 import android.net.vpn.VpnProfile;
 import android.net.vpn.VpnType;
 import android.os.Bundle;
@@ -158,10 +157,8 @@
     private VpnProfileEditor getEditor(VpnProfile p) {
         if (p instanceof L2tpIpsecProfile) {
             return new L2tpIpsecEditor((L2tpIpsecProfile) p);
-        } else if (p instanceof SingleServerProfile) {
-            return new SingleServerEditor((SingleServerProfile) p);
         } else {
-            throw new RuntimeException("Unknown profile type: " + p.getType());
+            return new VpnProfileEditor(p);
         }
     }
 
diff --git a/src/com/android/settings/vpn/VpnProfileEditor.java b/src/com/android/settings/vpn/VpnProfileEditor.java
index 686e513..a245263 100644
--- a/src/com/android/settings/vpn/VpnProfileEditor.java
+++ b/src/com/android/settings/vpn/VpnProfileEditor.java
@@ -16,20 +16,48 @@
 
 package com.android.settings.vpn;
 
+import com.android.settings.R;
+
 import android.content.Context;
 import android.net.vpn.VpnProfile;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
 import android.preference.PreferenceGroup;
 
 /**
- * The interface to set up preferences for editing a {@link VpnProfile}.
+ * The common class for editing {@link VpnProfile}.
  */
-public interface VpnProfileEditor {
-    VpnProfile getProfile();
+class VpnProfileEditor {
+    private EditTextPreference mServerName;
+    private EditTextPreference mDomainSuffices;
+    private VpnProfile mProfile;
+
+    public VpnProfileEditor(VpnProfile p) {
+        mProfile = p;
+    }
+
+    //@Override
+    public VpnProfile getProfile() {
+        return mProfile;
+    }
 
     /**
-     * Adds the preferences to the panel.
+     * Adds the preferences to the panel. Subclasses should override
+     * {@link #loadExtraPreferencesTo(PreferenceGroup)} instead of this method.
      */
-    void loadPreferencesTo(PreferenceGroup subpanel);
+    public void loadPreferencesTo(PreferenceGroup subpanel) {
+        Context c = subpanel.getContext();
+        subpanel.addPreference(createServerNamePreference(c));
+        loadExtraPreferencesTo(subpanel);
+        subpanel.addPreference(createDomainSufficesPreference(c));
+    }
+
+    /**
+     * Adds the extra preferences to the panel. Subclasses should add
+     * additional preferences in this method.
+     */
+    protected void loadExtraPreferencesTo(PreferenceGroup subpanel) {
+    }
 
     /**
      * Validates the inputs in the preferences.
@@ -37,5 +65,60 @@
      * @return an error message that is ready to be displayed in a dialog; or
      *      null if all the inputs are valid
      */
-    String validate(Context c);
+    public String validate(Context c) {
+        return (Util.isNullOrEmpty(mServerName.getText())
+                        ? c.getString(R.string.vpn_error_server_name_empty)
+                        : null);
+    }
+
+    /**
+     * Creates a preference for users to input domain suffices.
+     */
+    protected EditTextPreference createDomainSufficesPreference(Context c) {
+        EditTextPreference pref = mDomainSuffices = new EditTextPreference(c);
+        pref.setTitle(R.string.vpn_dns_search_list_title);
+        pref.setDialogTitle(R.string.vpn_dns_search_list_title);
+        pref.setPersistent(true);
+        pref.setText(mProfile.getDomainSuffices());
+        pref.setSummary(mProfile.getDomainSuffices());
+        pref.setOnPreferenceChangeListener(
+                new Preference.OnPreferenceChangeListener() {
+                    public boolean onPreferenceChange(
+                            Preference pref, Object newValue) {
+                        String v = ((String) newValue).trim();
+                        mProfile.setDomainSuffices(v);
+                        pref.setSummary(checkNull(v, pref.getContext()));
+                        return true;
+                    }
+                });
+        return pref;
+    }
+
+    private Preference createServerNamePreference(Context c) {
+        EditTextPreference serverName = mServerName = new EditTextPreference(c);
+        String title = c.getString(R.string.vpn_server_name_title);
+        serverName.setTitle(title);
+        serverName.setDialogTitle(title);
+        serverName.setSummary(checkNull(mProfile.getServerName(), c));
+        serverName.setText(mProfile.getServerName());
+        serverName.setPersistent(true);
+        serverName.setOnPreferenceChangeListener(
+                new Preference.OnPreferenceChangeListener() {
+                    public boolean onPreferenceChange(
+                            Preference pref, Object newValue) {
+                        String v = ((String) newValue).trim();
+                        mProfile.setServerName(v);
+                        pref.setSummary(checkNull(v, pref.getContext()));
+                        return true;
+                    }
+                });
+        return mServerName;
+    }
+
+
+   String checkNull(String value, Context c) {
+        return ((value != null && value.length() > 0)
+                ? value
+                : c.getString(R.string.vpn_not_set));
+   }
 }