auto import from //branches/cupcake/...@130745
diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
new file mode 100644
index 0000000..47e005f
--- /dev/null
+++ b/src/com/android/settings/ActivityPicker.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.LauncherActivity;
+import android.content.Intent;
+import android.os.Parcelable;
+import android.view.View;
+import android.widget.ListView;
+
+/**
+ * Displays a list of all activities matching the incoming {@link Intent.EXTRA_INTENT}
+ * query, along with any applicable icons. 
+ */
+public class ActivityPicker extends LauncherActivity {
+    
+    @Override
+    protected Intent getTargetIntent() {
+        Intent intent = this.getIntent();
+        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+        targetIntent.addCategory(Intent.CATEGORY_DEFAULT);
+        
+        // Use a custom title for this dialog, if provided
+        if (intent.hasExtra(Intent.EXTRA_TITLE)) {
+            String title = intent.getStringExtra(Intent.EXTRA_TITLE);
+            setTitle(title);
+        }
+        
+        Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+        if (parcel instanceof Intent) {
+            targetIntent = (Intent) parcel;
+        }
+        
+        return targetIntent;
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        Intent intent = intentForPosition(position);
+        setResult(RESULT_OK, intent);
+        finish();
+    }
+
+}
diff --git a/src/com/android/settings/ApnSettings.java b/src/com/android/settings/ApnSettings.java
index 83efa3f..aab529c 100644
--- a/src/com/android/settings/ApnSettings.java
+++ b/src/com/android/settings/ApnSettings.java
@@ -25,6 +25,7 @@
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 import android.provider.Telephony;
 import android.text.TextUtils;
@@ -61,7 +62,7 @@
         mCursor = managedQuery(Telephony.Carriers.CONTENT_URI, new String[] {
                 "_id", "name", "apn"}, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
 
-        PreferenceCategory apnList = (PreferenceCategory) findPreference("apn_list");
+        PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
         apnList.removeAll();
         
         mCursor.moveToFirst();
diff --git a/src/com/android/settings/BatteryHistory.java b/src/com/android/settings/BatteryHistory.java
deleted file mode 100644
index 7e077d5..0000000
--- a/src/com/android/settings/BatteryHistory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2006 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 java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import com.android.internal.app.IBatteryStats;
-
-import android.app.Activity;
-import android.os.BatteryStats;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-import android.widget.TextView;
-
-public class BatteryHistory extends Activity {
-    private static final String TAG = "BatteryHistory";
-    TextView mTextView;
-    IBatteryStats mBatteryInfo;
-
-    private String getDump(BatteryStats stats) {
-        try {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            PrintWriter pw = new PrintWriter(out, true);
-            stats.dumpLocked(null, pw, null);
-            pw.flush();
-            pw.close();
-            out.close();
-            return new String(out.toByteArray(), 0);
-        } catch (IOException e) {
-            return "IOException";
-        }
-    }
-    
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        Log.i(TAG, "onCreate");
-        setContentView(R.layout.battery_history);
-        mTextView = (TextView) findViewById(R.id.text);
-        mBatteryInfo = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
-        try {
-            BatteryStats stats = mBatteryInfo.getStatistics();
-            String s = getDump(stats);
-            mTextView.setText(s);
-        } catch (RemoteException e) {
-            mTextView.setText("Got RemoteException");
-            Log.e(TAG, "RemoteException:", e);
-        }
-    }
-}
diff --git a/src/com/android/settings/DateTimeSettings.java b/src/com/android/settings/DateTimeSettings.java
index ead38d1..e78215a 100644
--- a/src/com/android/settings/DateTimeSettings.java
+++ b/src/com/android/settings/DateTimeSettings.java
@@ -192,6 +192,7 @@
         }
     }
 
+    @Override
     public Dialog onCreateDialog(int id) {
         Dialog d;
 
@@ -226,6 +227,7 @@
         return d;
     }
 
+    @Override
     public void onPrepareDialog(int id, Dialog d) {
         switch (id) {
         case DIALOG_DATEPICKER: {
@@ -250,10 +252,13 @@
         }
     }
     
+    @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
         if (preference == mDatePref) {
             showDialog(DIALOG_DATEPICKER);
         } else if (preference == mTimePref) {
+            // The 24-hour mode may have changed, so recreate the dialog
+            removeDialog(DIALOG_TIMEPICKER);
             showDialog(DIALOG_TIMEPICKER);
         } else if (preference == mTime24Pref) {
             set24Hour(((CheckBoxPreference)mTime24Pref).isChecked());
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 5d72afc..3697319 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -20,6 +20,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemProperties;
 import android.preference.Preference;
@@ -54,10 +55,10 @@
         
         addPreferencesFromResource(R.xml.device_info_settings);
        
-        setSummary("firmware_version", "ro.build.version.release");
-        setSummary("baseband_version", "gsm.version.baseband");
-        setSummary("device_model", "ro.product.model");
-        setSummary("build_number", "ro.build.version.incremental");
+        setStringSummary("firmware_version", Build.VERSION.RELEASE);
+        setValueSummary("baseband_version", "gsm.version.baseband");
+        setStringSummary("device_model", Build.MODEL);
+        setStringSummary("build_number", Build.DISPLAY);
         findPreference("kernel_version").setSummary(getFormattedKernelVersion());
 
         /*
@@ -79,13 +80,22 @@
                 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
     }
     
-    private void setSummary(String preference, String property) {
+    private void setStringSummary(String preference, String value) {
+        try {
+            findPreference(preference).setSummary(value);
+        } catch (RuntimeException e) {
+            findPreference(preference).setSummary(
+                getResources().getString(R.string.device_info_default));
+        }
+    }
+    
+    private void setValueSummary(String preference, String property) {
         try {
             findPreference(preference).setSummary(
                     SystemProperties.get(property, 
                             getResources().getString(R.string.device_info_default)));
         } catch (RuntimeException e) {
-            
+
         }
     }
 
diff --git a/src/com/android/settings/GadgetPickActivity.java b/src/com/android/settings/GadgetPickActivity.java
new file mode 100644
index 0000000..09e0fc7
--- /dev/null
+++ b/src/com/android/settings/GadgetPickActivity.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 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.LauncherActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.gadget.GadgetInfo;
+import android.gadget.GadgetManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ListView;
+import android.util.Log;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class GadgetPickActivity extends LauncherActivity
+{
+    private static final String TAG = "GadgetPickActivity";
+
+    GadgetManager mGadgetManager;
+    int mGadgetId;
+    int mHostId;
+    
+    public GadgetPickActivity() {
+        mGadgetManager = GadgetManager.getInstance(this);
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        Bundle extras = getIntent().getExtras();
+        mHostId = extras.getInt(GadgetManager.EXTRA_HOST_ID);
+        mGadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID);
+
+        setResultData(RESULT_CANCELED);
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id)
+    {
+        Intent intent = intentForPosition(position);
+        mGadgetManager.bindGadgetId(mGadgetId, intent.getComponent());
+        setResultData(RESULT_OK);
+        finish();
+    }
+    
+    @Override
+    public List<ListItem> makeListItems() {
+        List<GadgetInfo> installed = mGadgetManager.getInstalledProviders();
+        PackageManager pm = getPackageManager();
+
+        Drawable defaultIcon = null;
+        IconResizer resizer = new IconResizer();
+
+        ArrayList<ListItem> result = new ArrayList();
+        final int N = installed.size();
+        for (int i=0; i<N; i++) {
+            GadgetInfo info = installed.get(i);
+
+            LauncherActivity.ListItem item = new LauncherActivity.ListItem();
+            item.packageName = info.provider.getPackageName();
+            item.className = info.provider.getClassName();
+            
+            item.label = info.label;
+            if (info.icon != 0) {
+                Drawable d = pm.getDrawable( item.packageName, info.icon, null);
+                if (d != null) {
+                    item.icon = resizer.createIconThumbnail(d);
+                } else {
+                    Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+                            + " for package: " + item.packageName);
+                }
+            }
+            if (item.icon == null) {
+                // (including error case above)
+                if (defaultIcon == null) {
+                    // TODO: Load standard icon.
+                }
+                item.icon = defaultIcon;
+            }
+            
+            result.add(item);
+        }
+        return result;
+    }
+    
+    void setResultData(int code) {
+        Intent result = new Intent();
+        result.putExtra(GadgetManager.EXTRA_GADGET_ID, mGadgetId);
+        setResult(code, result);
+    }
+}
+
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
index 04121bb..d4dfe97 100644
--- a/src/com/android/settings/InstalledAppDetails.java
+++ b/src/com/android/settings/InstalledAppDetails.java
@@ -66,6 +66,7 @@
     private Button mActivitiesButton;
     private boolean mCanUninstall;
     private boolean localLOGV=Config.LOGV || false;
+    private TextView mAppSnippetSize;
     private TextView mTotalSize;
     private TextView mAppSize;
     private TextView mDataSize;
@@ -76,6 +77,7 @@
     private TextView mCacheSize;
     private Button mClearCacheButton;
     private ClearCacheObserver mClearCacheObserver;
+    private Button mForceStopButton;
     
     PackageStats mSizeInfo;
     private Button mManageSpaceButton;
@@ -227,10 +229,8 @@
             appName = getString(_UNKNOWN_APP);
         }
         ((TextView)findViewById(R.id.app_name)).setText(appName);
-        CharSequence appDesc = mAppInfo.loadDescription(mPm);
-        if(appDesc != null) {
-            ((TextView)findViewById(R.id.app_description)).setText(appDesc);
-        }
+        mAppSnippetSize = ((TextView)findViewById(R.id.app_size));
+        mAppSnippetSize.setText(totalSizeStr);
         //TODO download str and download url
         //set values on views
         mTotalSize = (TextView)findViewById(R.id.total_size_text);
@@ -255,6 +255,8 @@
          mCachePanel = findViewById(R.id.cache_panel);
          mCacheSize = (TextView) findViewById(R.id.cache_size_text);
          mClearCacheButton = (Button) findViewById(R.id.clear_cache_button);
+         mForceStopButton = (Button) findViewById(R.id.force_stop_button);
+         mForceStopButton.setOnClickListener(this);
          
          //clear activities
          mActivitiesButton = (Button)findViewById(R.id.clear_activities_button);
@@ -326,13 +328,17 @@
         long newTot = newPs.cacheSize+newPs.codeSize+newPs.dataSize;
         if(mSizeInfo == null) {
             mSizeInfo = newPs;
-            mTotalSize.setText(getSizeStr(newTot));
+            String str = getSizeStr(newTot);
+            mTotalSize.setText(str);
+            mAppSnippetSize.setText(str);
             mAppSize.setText(getSizeStr(newPs.codeSize));
             mDataSize.setText(getSizeStr(newPs.dataSize+newPs.cacheSize));
         } else {
             long oldTot = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
             if(newTot != oldTot) {
-                mTotalSize.setText(getSizeStr(newTot));
+                String str = getSizeStr(newTot);
+                mTotalSize.setText(str);
+                mAppSnippetSize.setText(str);
                 changed = true;
             }
             if(newPs.codeSize != mSizeInfo.codeSize) {
@@ -446,6 +452,10 @@
                 mClearCacheObserver = new ClearCacheObserver();
             }
             mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
+        } else if (v == mForceStopButton) {
+            ActivityManager am = (ActivityManager)getSystemService(
+                    Context.ACTIVITY_SERVICE);
+            am.restartPackage(packageName);
         }
     }
 
diff --git a/src/com/android/settings/LanguageSettings.java b/src/com/android/settings/LanguageSettings.java
index 2777777..b406df6 100644
--- a/src/com/android/settings/LanguageSettings.java
+++ b/src/com/android/settings/LanguageSettings.java
@@ -17,6 +17,7 @@
 package com.android.settings;
 
 import android.content.ContentResolver;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
@@ -58,11 +59,17 @@
                 removePreference(findPreference("language_category"));
         }
     
-        ContentResolver resolver = getContentResolver();
-        for (int i = 0; i < mSettingsUiKey.length; i++) {
-            CheckBoxPreference pref = (CheckBoxPreference) findPreference(mSettingsUiKey[i]);
-            pref.setChecked(System.getInt(resolver, mSettingsSystemId[i],
-                                          mSettingsDefault[i]) > 0);
+        Configuration config = getResources().getConfiguration();
+        if (config.keyboard != Configuration.KEYBOARD_QWERTY) {
+            getPreferenceScreen().removePreference(
+                    getPreferenceScreen().findPreference("hardkeyboard_category"));
+        } else {
+            ContentResolver resolver = getContentResolver();
+            for (int i = 0; i < mSettingsUiKey.length; i++) {
+                CheckBoxPreference pref = (CheckBoxPreference) findPreference(mSettingsUiKey[i]);
+                pref.setChecked(System.getInt(resolver, mSettingsSystemId[i],
+                                              mSettingsDefault[i]) > 0);
+            }
         }
     }
     
diff --git a/src/com/android/settings/LocalePicker.java b/src/com/android/settings/LocalePicker.java
index 9ee8260..386d7e0 100644
--- a/src/com/android/settings/LocalePicker.java
+++ b/src/com/android/settings/LocalePicker.java
@@ -73,14 +73,14 @@
             int len = s.length();
             if (len == 2) {
                 Locale l = new Locale(s);
-                preprocess[finalSize++] = new Loc(l.getDisplayLanguage(), l);
+                preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayLanguage()), l);
             } else if (len == 5) {
                 String language = s.substring(0, 2);
                 String country = s.substring(3, 5);
                 Locale l = new Locale(language, country);
 
                 if (finalSize == 0) {
-                    preprocess[finalSize++] = new Loc(l.getDisplayLanguage(), l);
+                    preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayLanguage()), l);
                 } else {
                     // check previous entry:
                     //  same lang and no country -> overwrite it with a lang-only name
@@ -91,17 +91,17 @@
                        String prevCountry = preprocess[finalSize-1].locale.getCountry();
                        if (prevCountry.length() == 0) {
                             preprocess[finalSize-1].locale = l;
-                            preprocess[finalSize-1].label = l.getDisplayLanguage();
+                            preprocess[finalSize-1].label = toTitleCase(l.getDisplayLanguage());
                         } else {
-                            preprocess[finalSize-1].label = preprocess[finalSize-1].locale.getDisplayName();
-                            preprocess[finalSize++] = new Loc(l.getDisplayName(), l);
+                            preprocess[finalSize-1].label = toTitleCase(preprocess[finalSize-1].locale.getDisplayName());
+                            preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayName()), l);
                         }
                     } else {
                         String displayName;
                         if (s.equals("zz_ZZ")) {
                             displayName = "Pseudo...";
                         } else {
-                            displayName = l.getDisplayLanguage();
+                            displayName = toTitleCase(l.getDisplayLanguage());
                         }
                         preprocess[finalSize++] = new Loc(displayName, l);
                     }
@@ -118,6 +118,14 @@
         getListView().setAdapter(adapter);
     }
 
+    private static String toTitleCase(String s) {
+        if (s.length() == 0) {
+            return s;
+        }
+
+        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+    }
+
     @Override
     public void onResume() {
         super.onResume();
diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java
index f1550f9..e5311ae 100644
--- a/src/com/android/settings/ManageApplications.java
+++ b/src/com/android/settings/ManageApplications.java
@@ -17,8 +17,8 @@
 package com.android.settings;
 
 import com.android.settings.R;
-import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.AlertDialog;
 import android.app.ListActivity;
 import android.app.ProgressDialog;
 import android.content.BroadcastReceiver;
@@ -90,7 +90,8 @@
  *  InstalledAppDetailsActivity to avoid recomputation of the package size information.
  */
 public class ManageApplications extends ListActivity implements
-        OnItemClickListener, DialogInterface.OnCancelListener {
+        OnItemClickListener, DialogInterface.OnCancelListener,
+        DialogInterface.OnClickListener {
     // TAG for this activity
     private static final String TAG = "ManageApplications";
     
@@ -119,6 +120,9 @@
     public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 2;
     public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 3;
     public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 4;
+    public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 5;
+    // Alert Dialog presented to user to find out the filter option
+    AlertDialog.Builder mAlertDlgBuilder;
     // sort order
     private int mSortOrder = SORT_ORDER_ALPHA;
     // Filter value
@@ -295,11 +299,7 @@
                         // end computation here
                         mDoneIniting = true;
                         mAppInfoAdapter.sortList(mSortOrder);
-                        //load resources now
-                        if(mResourceThread.isAlive()) {
-                            mResourceThread.interrupt();
-                        }
-                        mResourceThread.loadAllResources(mAppInfoAdapter.getAppList());
+                        setProgressBarIndeterminateVisibility(false);
                     }
                 }
                 break;
@@ -381,7 +381,15 @@
                     Log.w(TAG, "Error loading icons for applications");
                 } else {
                     mAppInfoAdapter.updateAppsResourceInfo(iconMap);
-                    setProgressBarIndeterminateVisibility(false);
+                }
+                // initiate compute pkg sizes
+                if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
+                mObserver = new PkgSizeObserver();
+                if (mAppInfoAdapter.getCount() > 0) {
+                    mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo(0),
+                            COMPUTE_PKG_SIZE_DONE);
+                } else {
+                    mDoneIniting = true;
                 }
             default:
                 break;
@@ -398,7 +406,15 @@
         if (filterOption == FILTER_APPS_THIRD_PARTY) {
             List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
             for (ApplicationInfo appInfo : installedAppList) {
+                boolean flag = false;
                 if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                    // Updated system app
+                    flag = true;
+                } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    // Non-system app
+                    flag = true;
+                }
+                if (flag) {
                     appList.add(appInfo);
                 }
             }
@@ -457,14 +473,11 @@
         // register receiver
         mReceiver = new PackageIntentReceiver();
         mReceiver.registerReceiver();
-        // initiate compute pkg sizes
-        if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
-        mObserver = new PkgSizeObserver();
-        if(appList.size() > 0) {
-            mObserver.invokeGetSizeInfo(appList.get(0), COMPUTE_PKG_SIZE_DONE);
-        } else {
-            mDoneIniting = true;
+        //load resources now
+        if(mResourceThread.isAlive()) {
+            mResourceThread.interrupt();
         }
+        mResourceThread.loadAllResources(appList);
     }
     
     // internal structure used to track added and deleted packages when
@@ -717,7 +730,9 @@
                 if(mInfo.appIcon != null) {
                     holder.appIcon.setImageDrawable(mInfo.appIcon);
                 }
-                holder.appSize.setText(mInfo.appSize);
+                if (mInfo.appSize != null) {
+                    holder.appSize.setText(mInfo.appSize);
+                }
             } else {
                 Log.w(TAG, "No info for package:"+appInfo.packageName+" in property map");
             }
@@ -1123,9 +1138,7 @@
                 .setIcon(android.R.drawable.ic_menu_sort_alphabetically);
         menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
                 .setIcon(android.R.drawable.ic_menu_sort_by_size); 
-        menu.add(0, FILTER_APPS_ALL, 3, R.string.filter_apps_all);
-        menu.add(0, FILTER_APPS_RUNNING, 4, R.string.filter_apps_running);
-        menu.add(0, FILTER_APPS_THIRD_PARTY, 5, R.string.filter_apps_third_party);        
+        menu.add(0, FILTER_OPTIONS, 3, R.string.filter);
         return true;
     }
     
@@ -1134,11 +1147,7 @@
         if (mDoneIniting) {
             menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
             menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
-            menu.findItem(FILTER_APPS_ALL).setVisible(mFilterApps != FILTER_APPS_ALL);
-            menu.findItem(FILTER_APPS_THIRD_PARTY).setVisible(
-                    mFilterApps != FILTER_APPS_THIRD_PARTY);
-            menu.findItem(FILTER_APPS_RUNNING).setVisible(
-                    mFilterApps != FILTER_APPS_RUNNING);
+            menu.findItem(FILTER_OPTIONS).setVisible(true);
             return true;
         } 
         return false;
@@ -1147,7 +1156,20 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         int menuId = item.getItemId();
-        sendMessageToHandler(REORDER_LIST, menuId);
+        if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
+            sendMessageToHandler(REORDER_LIST, menuId);
+        } else if (menuId == FILTER_OPTIONS) {
+            if (mAlertDlgBuilder == null) {
+                mAlertDlgBuilder = new AlertDialog.Builder(this).
+                setTitle(R.string.filter_dlg_title).
+                setNeutralButton(R.string.cancel, this).
+                setSingleChoiceItems(new CharSequence[] {getText(R.string.filter_apps_all),
+                        getText(R.string.filter_apps_running),
+                        getText(R.string.filter_apps_third_party)},
+                        -1, this);
+            }
+            mAlertDlgBuilder.show();
+        }
         return true;
     }
 
@@ -1162,4 +1184,24 @@
         mLoadingDlg = null;
         finish();
     }
+
+    public void onClick(DialogInterface dialog, int which) {
+        int newOption;
+        switch (which) {
+        // Make sure that values of 0, 1, 2 match options all, running, third_party when
+        // created via the AlertDialog.Builder
+        case 0:
+            newOption = FILTER_APPS_ALL;
+            break;
+        case 1:
+            newOption = FILTER_APPS_RUNNING;
+            break;
+        case 2:
+            newOption = FILTER_APPS_THIRD_PARTY;
+            break;
+        default:
+            return;
+        }
+        sendMessageToHandler(REORDER_LIST, newOption);
+    }
 }
diff --git a/src/com/android/settings/MediaFormat.java b/src/com/android/settings/MediaFormat.java
new file mode 100644
index 0000000..3594572
--- /dev/null
+++ b/src/com/android/settings/MediaFormat.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2008 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 com.android.internal.widget.LockPatternUtils;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IMountService;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.os.Environment;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+
+/**
+ * Confirm and execute a format of the sdcard.
+ * Multiple confirmations are required: first, a general "are you sure
+ * you want to do this?" prompt, followed by a keyguard pattern trace if the user
+ * has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING
+ * ON THE SD CARD" prompt.  If at any time the phone is allowed to go to sleep, is
+ * locked, et cetera, then the confirmation sequence is abandoned.
+ */
+public class MediaFormat extends Activity {
+
+    private static final int KEYGUARD_REQUEST = 55;
+
+    private LayoutInflater mInflater;
+    private LockPatternUtils mLockUtils;
+
+    private View mInitialView;
+    private Button mInitiateButton;
+
+    private View mFinalView;
+    private Button mFinalButton;
+
+    /** 
+     * The user has gone through the multiple confirmation, so now we go ahead
+     * and invoke the Mount Service to format the SD card.
+     */
+    private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
+            public void onClick(View v) {
+                
+                // Those monkeys kept committing suicide, so we add this property
+                // to disable going through with the format
+                if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) {
+                    return;
+                }
+                IMountService service =
+                        IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+                if (service != null) {
+                    try {
+                        service.formatMedia(Environment.getExternalStorageDirectory().toString());
+                    } catch (android.os.RemoteException e) {
+                        // Intentionally blank - there's nothing we can do here
+                        Log.w("MediaFormat", "Unable to invoke IMountService.formatMedia()");
+                    }
+                } else {
+                    Log.w("MediaFormat", "Unable to locate IMountService");
+                }
+            finish();
+            }
+        };
+
+    /**
+     *  Keyguard validation is run using the standard {@link ConfirmLockPattern}
+     * component as a subactivity
+     */
+    private void runKeyguardConfirmation() {
+        final Intent intent = new Intent();
+        intent.setClassName("com.android.settings",
+                "com.android.settings.ConfirmLockPattern");
+        // supply header and footer text in the intent
+        intent.putExtra(ConfirmLockPattern.HEADER_TEXT,
+                getText(R.string.media_format_gesture_prompt));
+        intent.putExtra(ConfirmLockPattern.FOOTER_TEXT,
+                getText(R.string.media_format_gesture_explanation));
+        startActivityForResult(intent, KEYGUARD_REQUEST);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode != KEYGUARD_REQUEST) {
+            return;
+        }
+
+        // If the user entered a valid keyguard trace, present the final
+        // confirmation prompt; otherwise, go back to the initial state.
+        if (resultCode == Activity.RESULT_OK) {
+            establishFinalConfirmationState();
+        } else {
+            establishInitialState();
+        }
+    }
+
+    /**
+     * If the user clicks to begin the reset sequence, we next require a
+     * keyguard confirmation if the user has currently enabled one.  If there
+     * is no keyguard available, we simply go to the final confirmation prompt.
+     */
+    private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
+            public void onClick(View v) {
+                if (mLockUtils.isLockPatternEnabled()) {
+                    runKeyguardConfirmation();
+                } else {
+                    establishFinalConfirmationState();
+                }
+            }
+        };
+
+    /**
+     * Configure the UI for the final confirmation interaction
+     */
+    private void establishFinalConfirmationState() {
+        if (mFinalView == null) {
+            mFinalView = mInflater.inflate(R.layout.media_format_final, null);
+            mFinalButton =
+                    (Button) mFinalView.findViewById(R.id.execute_media_format);
+            mFinalButton.setOnClickListener(mFinalClickListener);
+        }
+
+        setContentView(mFinalView);
+    }
+
+    /**
+     * In its initial state, the activity presents a button for the user to
+     * click in order to initiate a confirmation sequence.  This method is
+     * called from various other points in the code to reset the activity to
+     * this base state.
+     * 
+     * <p>Reinflating views from resources is expensive and prevents us from
+     * caching widget pointers, so we use a single-inflate pattern:  we lazy-
+     * inflate each view, caching all of the widget pointers we'll need at the
+     * time, then simply reuse the inflated views directly whenever we need
+     * to change contents.
+     */
+    private void establishInitialState() {
+        if (mInitialView == null) {
+            mInitialView = mInflater.inflate(R.layout.media_format_primary, null);
+            mInitiateButton =
+                    (Button) mInitialView.findViewById(R.id.initiate_media_format);
+            mInitiateButton.setOnClickListener(mInitiateListener);
+        }
+
+        setContentView(mInitialView);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedState) {
+        super.onCreate(savedState);
+
+        mInitialView = null;
+        mFinalView = null;
+        mInflater = LayoutInflater.from(this);
+        mLockUtils = new LockPatternUtils(getContentResolver());
+
+        establishInitialState();
+    }
+
+    /** Abandon all progress through the confirmation sequence by returning
+     * to the initial view any time the activity is interrupted (e.g. by
+     * idle timeout).
+     */
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        establishInitialState();
+    }
+
+}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index b1ad777..b7ff28a 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -119,10 +119,12 @@
     private TextView mPingHostname;
     private TextView mHttpClientTest;
     private TextView cipherState;
+    private TextView dnsCheckState;
     private EditText smsc;
     private Button radioPowerButton;
     private Button qxdmLogButton;
     private Button cipherToggleButton;
+    private Button dnsCheckToggleButton;
     private Button pingTestButton;
     private Button updateSmscButton;
     private Button refreshSmscButton;
@@ -428,6 +430,7 @@
         received = (TextView) findViewById(R.id.received);
         cipherState = (TextView) findViewById(R.id.ciphState);
         smsc = (EditText) findViewById(R.id.smsc);
+        dnsCheckState = (TextView) findViewById(R.id.dnsCheckState);
 
         mPingIpAddr = (TextView) findViewById(R.id.pingIpAddr);
         mPingHostname = (TextView) findViewById(R.id.pingHostname);
@@ -454,6 +457,8 @@
         updateSmscButton.setOnClickListener(mUpdateSmscButtonHandler);
         refreshSmscButton = (Button) findViewById(R.id.refresh_smsc);
         refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
+        dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
+        dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
         
         mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
         mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
@@ -490,6 +495,7 @@
         updateQxdmState(null);
         updateProperties();
         updateCiphState();
+        updateDnsCheckState();
 
         Log.i(TAG, "[RadioInfo] onResume: register phone & data intents");
 
@@ -614,6 +620,12 @@
         cipherState.setText(getCiphPref() ? "Ciphering ON" : "Ciphering OFF");
     }
 
+    private void updateDnsCheckState() {
+        GSMPhone gsmPhone = (GSMPhone) phone;
+        dnsCheckState.setText(gsmPhone.isDnsCheckDisabled() ?
+                "0.0.0.0 allowed" :"0.0.0.0 not allowed");
+    }
+    
     private final void
     updateSignalStrength() {
         int state =
@@ -806,10 +818,10 @@
         Resources r = getResources();
 
         try {
-            int txPackets = netstat.getTxPackets();
-            int rxPackets = netstat.getRxPackets();
-            int txBytes   = netstat.getTxBytes();
-            int rxBytes   = netstat.getRxBytes();
+            long txPackets = netstat.getMobileTxPackets();
+            long rxPackets = netstat.getMobileRxPackets();
+            long txBytes   = netstat.getMobileTxBytes();
+            long rxBytes   = netstat.getMobileRxBytes();
     
             String packets = r.getString(R.string.radioInfo_display_packets);
             String bytes   = r.getString(R.string.radioInfo_display_bytes);
@@ -1114,6 +1126,14 @@
         }
     };
     
+    OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            GSMPhone gsmPhone = (GSMPhone) phone;
+            gsmPhone.disableDnsCheck(!gsmPhone.isDnsCheckDisabled());
+            updateDnsCheckState();
+        }
+    };
+    
     OnClickListener mPingButtonHandler = new OnClickListener() {
         public void onClick(View v) {
             updatePingState();
diff --git a/src/com/android/settings/SdCardErrorReceiver.java b/src/com/android/settings/SdCardErrorReceiver.java
deleted file mode 100644
index ba35a3c..0000000
--- a/src/com/android/settings/SdCardErrorReceiver.java
+++ /dev/null
@@ -1,45 +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;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
-import android.util.Log;
-import android.widget.Toast;
-
-
-/**
- * Glue class: connects AlarmAlert IntentReceiver to AlarmAlert
- * activity.  Passes through Alarm ID.
- */
-public class SdCardErrorReceiver extends BroadcastReceiver {
-
-    private static final String TAG = "SdCardErrorReceiver";
-
-    @Override public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        final int duration = 3500;
-        if (action.equals(Intent.ACTION_MEDIA_BAD_REMOVAL)) {
-            Toast.makeText(context, R.string.sdcard_removal_alert_title, duration).show();
-        } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTABLE)) {
-            Toast.makeText(context, R.string.sdcard_unmountable_alert_title, duration).show();
-        } else {
-            Log.e(TAG, "unknown intent");
-        }
-    }
-}
diff --git a/src/com/android/settings/SdCardSettings.java b/src/com/android/settings/SdCardSettings.java
index d10166a..b6935a2 100644
--- a/src/com/android/settings/SdCardSettings.java
+++ b/src/com/android/settings/SdCardSettings.java
@@ -60,6 +60,9 @@
         Button unmountButton = (Button)findViewById(R.id.sdcard_unmount);
         unmountButton.setOnClickListener(mUnmountButtonHandler);
 
+        Button formatButton = (Button)findViewById(R.id.sdcard_format);
+        formatButton.setOnClickListener(mFormatButtonHandler);
+
         mTotalSize = (TextView)findViewById(R.id.total);
         mUsedSize = (TextView)findViewById(R.id.used);
         mAvailableSize = (TextView)findViewById(R.id.available);
@@ -69,6 +72,8 @@
         intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_SHARED);
+        intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING);
+        intentFilter.addAction(Intent.ACTION_MEDIA_NOFS);
         intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
@@ -198,6 +203,15 @@
         }
     };
 
+    OnClickListener mFormatButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            try {
+                mMountService.formatMedia(Environment.getExternalStorageDirectory().toString());
+            } catch (RemoteException ex) {
+            }
+        }
+    };
+
 
     private int         mStatus;
     private IMountService   mMountService;
diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundAndDisplaySettings.java
index 134e84f..53912e3 100644
--- a/src/com/android/settings/SoundAndDisplaySettings.java
+++ b/src/com/android/settings/SoundAndDisplaySettings.java
@@ -25,6 +25,7 @@
 import android.content.IntentFilter;
 import android.media.AudioManager;
 import android.os.Bundle;
+import android.os.IMountService;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.preference.ListPreference;
@@ -49,8 +50,21 @@
     private static final String KEY_DTMF_TONE = "dtmf_tone";
     private static final String KEY_SOUND_EFFECTS = "sound_effects";
     private static final String KEY_ANIMATIONS = "animations";
+    private static final String KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS = "play_media_notification_sounds";
     
     private CheckBoxPreference mSilent;
+
+    private CheckBoxPreference mPlayMediaNotificationSounds;
+
+    private IMountService mMountService = null;
+
+    /*
+     * If we are currently in one of the silent modes (the ringer mode is set to either
+     * "silent mode" or "vibrate mode"), then toggling the "Phone vibrate"
+     * preference will switch between "silent mode" and "vibrate mode".
+     * Otherwise, it will adjust the normal ringer mode's ring or ring+vibrate
+     * setting.
+     */
     private CheckBoxPreference mVibrate;
     private CheckBoxPreference mDtmfTone;
     private CheckBoxPreference mSoundEffects;
@@ -64,14 +78,7 @@
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            
-            int ringerMode = intent
-                    .getIntExtra(AudioManager.EXTRA_RINGER_MODE, AudioManager.RINGER_MODE_NORMAL);
-            boolean isSilentMode = ringerMode != AudioManager.RINGER_MODE_NORMAL;
-            
-            if (mSilent.isChecked() != isSilentMode) {
-                mSilent.setChecked(isSilentMode);
-            }
+            updateState(false);
         }
     };
 
@@ -82,10 +89,14 @@
         
         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
         mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+
+        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
         
         addPreferencesFromResource(R.xml.sound_and_display_settings);
         
         mSilent = (CheckBoxPreference) findPreference(KEY_SILENT);
+        mPlayMediaNotificationSounds = (CheckBoxPreference) findPreference(KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS);
+
         mVibrate = (CheckBoxPreference) findPreference(KEY_VIBRATE);
         mDtmfTone = (CheckBoxPreference) findPreference(KEY_DTMF_TONE);
         mDtmfTone.setPersistent(false);
@@ -123,17 +134,28 @@
     }
 
     private void updateState(boolean force) {
-        final boolean silent = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
-        final boolean phoneVibrate = mAudioManager
-                .getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER)
-                        == AudioManager.VIBRATE_SETTING_ON;
+        final int ringerMode = mAudioManager.getRingerMode();
+        final boolean silentOrVibrateMode =
+                ringerMode != AudioManager.RINGER_MODE_NORMAL;
         
-        if (silent != mSilent.isChecked() || force) {
-            mSilent.setChecked(silent);
+        if (silentOrVibrateMode != mSilent.isChecked() || force) {
+            mSilent.setChecked(silentOrVibrateMode);
         }
-        
-        if (phoneVibrate != mVibrate.isChecked() || force) {
-            mVibrate.setChecked(phoneVibrate);
+
+        try {
+            mPlayMediaNotificationSounds.setChecked(mMountService.getPlayNotificationSounds());
+        } catch (RemoteException e) {
+        }
+       
+        boolean vibrateSetting;
+        if (silentOrVibrateMode) {
+            vibrateSetting = ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+        } else {
+            vibrateSetting = mAudioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER)
+                    == AudioManager.VIBRATE_SETTING_ON;            
+        }
+        if (vibrateSetting != mVibrate.isChecked() || force) {
+            mVibrate.setChecked(vibrateSetting);
         }
         
         boolean animations = true;
@@ -161,12 +183,26 @@
             final boolean silent = mSilent.isChecked();
             mAudioManager.setRingerMode(silent ? AudioManager.RINGER_MODE_SILENT
                     : AudioManager.RINGER_MODE_NORMAL);
+            updateState(false);
             
+        } else if (preference == mPlayMediaNotificationSounds) {
+            try {
+                mMountService.setPlayNotificationSounds(mPlayMediaNotificationSounds.isChecked());
+            } catch (RemoteException e) {
+            }
         } else if (preference == mVibrate) {
             final boolean vibrate = mVibrate.isChecked();
-            mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
-                    vibrate ? AudioManager.VIBRATE_SETTING_ON
-                            : AudioManager.VIBRATE_SETTING_OFF);
+            final boolean silent = mSilent.isChecked();
+            
+            if (silent) {
+                mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE :
+                    AudioManager.RINGER_MODE_SILENT);                
+            } else {
+                mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
+                        vibrate ? AudioManager.VIBRATE_SETTING_ON
+                                : AudioManager.VIBRATE_SETTING_OFF);
+            }
+            
         } else if (preference == mDtmfTone) {
             Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
                     mDtmfTone.isChecked() ? 1 : 0);
diff --git a/src/com/android/settings/UsageStats.java b/src/com/android/settings/UsageStats.java
new file mode 100755
index 0000000..89caa54
--- /dev/null
+++ b/src/com/android/settings/UsageStats.java
@@ -0,0 +1,249 @@
+
+
+/**
+ * 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;
+
+import com.android.internal.app.IUsageStats;
+import com.android.settings.R;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.os.PkgUsageStats;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+/**
+ * Activity to display package usage statistics.
+ */
+public class UsageStats extends Activity implements OnItemSelectedListener {
+    private static final String TAG="UsageStatsActivity";
+    private static final boolean localLOGV = true;
+    private Spinner mTypeSpinner;
+    private ListView mListView;
+    private IUsageStats mUsageStatsService;
+    private LayoutInflater mInflater;
+    private UsageStatsAdapter mAdapter;
+    private PackageManager mPm;
+    
+    public static class AppNameComparator implements Comparator<PkgUsageStats> {
+        Map<String, CharSequence> mAppLabelList;
+        AppNameComparator(Map<String, CharSequence> appList) {
+            mAppLabelList = appList;
+        }
+        public final int compare(PkgUsageStats a, PkgUsageStats b) {
+            String alabel = mAppLabelList.get(a.packageName).toString();
+            String blabel = mAppLabelList.get(b.packageName).toString();
+            return alabel.compareTo(blabel);
+        }
+    }
+    
+    public static class LaunchCountComparator implements Comparator<PkgUsageStats> {
+        public final int compare(PkgUsageStats a, PkgUsageStats b) {
+            // return by descending order
+            return b.launchCount - a.launchCount;
+        }
+    }
+    
+    public static class UsageTimeComparator implements Comparator<PkgUsageStats> {
+        public final int compare(PkgUsageStats a, PkgUsageStats b) {
+            long ret = a.usageTime-b.usageTime;
+            if (ret == 0) {
+                return 0;
+            }
+            if (ret < 0) {
+                return 1;
+            }
+            return -1;
+        }
+    }
+    
+     // View Holder used when displaying views
+    static class AppViewHolder {
+        TextView pkgName;
+        TextView launchCount;
+        TextView usageTime;
+    }
+    
+    class UsageStatsAdapter extends BaseAdapter {
+         // Constants defining order for display order
+        private static final int _DISPLAY_ORDER_USAGE_TIME = 0;
+        private static final int _DISPLAY_ORDER_LAUNCH_COUNT = 1;
+        private static final int _DISPLAY_ORDER_APP_NAME = 2;
+        
+        private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME;
+        private List<PkgUsageStats> mUsageStats;
+        private LaunchCountComparator mLaunchCountComparator;
+        private UsageTimeComparator mUsageTimeComparator;
+        private AppNameComparator mAppLabelComparator;
+        private HashMap<String, CharSequence> mAppLabelMap;
+        
+        UsageStatsAdapter() {
+            mUsageStats = new ArrayList<PkgUsageStats>();
+            mAppLabelMap = new HashMap<String, CharSequence>();
+            PkgUsageStats[] stats;
+            try {
+                stats = mUsageStatsService.getAllPkgUsageStats();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed initializing usage stats service");
+                return;
+            }
+           if (stats == null) {
+               return;
+           }
+           for (PkgUsageStats ps : stats) {
+               mUsageStats.add(ps);
+               // load application labels for each application
+               CharSequence label;
+               try {
+                   ApplicationInfo appInfo = mPm.getApplicationInfo(ps.packageName, 0);
+                   label = appInfo.loadLabel(mPm);
+                } catch (NameNotFoundException e) {
+                    label = ps.packageName;
+                }
+                mAppLabelMap.put(ps.packageName, label);
+           }
+           // Sort list
+           mLaunchCountComparator = new LaunchCountComparator();
+           mUsageTimeComparator = new UsageTimeComparator();
+           mAppLabelComparator = new AppNameComparator(mAppLabelMap);
+           sortList();
+        }
+        public int getCount() {
+            return mUsageStats.size();
+        }
+
+        public Object getItem(int position) {
+            return mUsageStats.get(position);
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            // A ViewHolder keeps references to children views to avoid unneccessary calls
+            // to findViewById() on each row.
+            AppViewHolder holder;
+
+            // When convertView is not null, we can reuse it directly, there is no need
+            // to reinflate it. We only inflate a new View when the convertView supplied
+            // by ListView is null.
+            if (convertView == null) {
+                convertView = mInflater.inflate(R.layout.usage_stats_item, null);
+
+                // Creates a ViewHolder and store references to the two children views
+                // we want to bind data to.
+                holder = new AppViewHolder();
+                holder.pkgName = (TextView) convertView.findViewById(R.id.package_name);
+                holder.launchCount = (TextView) convertView.findViewById(R.id.launch_count);
+                holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time);
+                convertView.setTag(holder);
+            } else {
+                // Get the ViewHolder back to get fast access to the TextView
+                // and the ImageView.
+                holder = (AppViewHolder) convertView.getTag();
+            }
+
+            // Bind the data efficiently with the holder
+            PkgUsageStats pkgStats = mUsageStats.get(position);
+            if (pkgStats != null) {
+                CharSequence label = mAppLabelMap.get(pkgStats.packageName);
+                holder.pkgName.setText(label);
+                holder.launchCount.setText(String.valueOf(pkgStats.launchCount));
+                holder.usageTime.setText(String.valueOf(pkgStats.usageTime)+" ms");
+            } else {
+                Log.w(TAG, "No usage stats info for package:"+pkgStats.packageName);
+            }
+            return convertView;
+        }
+        
+        void sortList(int sortOrder) {
+            if (mDisplayOrder == sortOrder) {
+                // do nothing
+                return;
+            }
+            mDisplayOrder= sortOrder;
+            sortList();
+        }
+        private void sortList() {
+            if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) {
+                if (localLOGV) Log.i(TAG, "Sorting by usage time");
+                Collections.sort(mUsageStats, mUsageTimeComparator);
+            } else if (mDisplayOrder == _DISPLAY_ORDER_LAUNCH_COUNT) {
+                if (localLOGV) Log.i(TAG, "Sorting launch count");
+                Collections.sort(mUsageStats, mLaunchCountComparator);
+            } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) {
+                if (localLOGV) Log.i(TAG, "Sorting by application name");
+                Collections.sort(mUsageStats, mAppLabelComparator);
+            }
+            notifyDataSetChanged();
+        }
+    }
+
+    /** Called when the activity is first created. */
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mUsageStatsService = IUsageStats.Stub.asInterface(ServiceManager.getService("usagestats"));
+        if (mUsageStatsService == null) {
+            Log.e(TAG, "Failed to retrieve usagestats service");
+            return;
+        }
+        mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mPm = getPackageManager();
+        
+        setContentView(R.layout.usage_stats);
+        mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner);
+        mTypeSpinner.setOnItemSelectedListener(this);
+        
+        mListView = (ListView) findViewById(R.id.pkg_list);
+        // Initialize the inflater
+        
+        mAdapter = new UsageStatsAdapter();
+        mListView.setAdapter(mAdapter);
+    }
+
+    public void onItemSelected(AdapterView<?> parent, View view, int position,
+            long id) {
+        mAdapter.sortList(position);
+    }
+
+    public void onNothingSelected(AdapterView<?> parent) {
+        // do nothing
+    }
+}
+
diff --git a/src/com/android/settings/UserDictionarySettings.java b/src/com/android/settings/UserDictionarySettings.java
index 5d3c8ac..8b86a6b 100644
--- a/src/com/android/settings/UserDictionarySettings.java
+++ b/src/com/android/settings/UserDictionarySettings.java
@@ -21,6 +21,7 @@
 import android.app.ListActivity;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.provider.UserDictionary;
@@ -54,6 +55,8 @@
             + UserDictionary.Words.LOCALE + " is null";
 
     private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?";
+
+    private static final String EXTRA_WORD = "word";
     
     private static final int CONTEXT_MENU_EDIT = Menu.FIRST;
     private static final int CONTEXT_MENU_DELETE = Menu.FIRST + 1;
@@ -87,6 +90,16 @@
     }
     
     @Override
+    protected void onResume() {
+        super.onResume();
+        if (getIntent().getAction().equals("com.android.settings.USER_DICTIONARY_INSERT")) {
+            String word = getIntent().getStringExtra(EXTRA_WORD);
+            if (word != null) {
+                showAddOrEditDialog(word);
+            }
+        }
+    }
+    @Override
     protected void onRestoreInstanceState(Bundle state) {
         super.onRestoreInstanceState(state);
         mDialogEditingWord = state.getString(INSTANCE_KEY_DIALOG_EDITING_WORD);
@@ -207,7 +220,7 @@
         
         // TODO: present UI for picking whether to add word to all locales, or current.
         UserDictionary.Words.addWord(this, word.toString(),
-                1, UserDictionary.Words.LOCALE_TYPE_ALL);
+                128, UserDictionary.Words.LOCALE_TYPE_ALL);
         mCursor.requery();
     }
 
diff --git a/src/com/android/settings/battery_history/BatteryHistory.java b/src/com/android/settings/battery_history/BatteryHistory.java
new file mode 100644
index 0000000..19302a5
--- /dev/null
+++ b/src/com/android/settings/battery_history/BatteryHistory.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2006 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.battery_history;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.settings.R;
+
+import android.app.Activity;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.BatteryStats.Timer;
+import android.os.BatteryStats.Uid;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+public class BatteryHistory extends Activity implements OnClickListener, OnItemSelectedListener {
+    private static final String TAG = "BatteryHistory";
+
+    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;
+    
+    // Must be in sync with the values in res/values/array.xml (id battery_history_type_spinner)
+    private static final int CPU_USAGE = 0;
+    private static final int NETWORK_USAGE = 1;
+    private static final int SENSOR_USAGE = 2;
+    private static final int SCREEN_ON = 3;
+    private static final int WAKE_LOCKS = 4;
+
+    // App names to use as labels for the shared UIDs that contain them
+    private final HashSet<String> mKnownApps = new HashSet<String>();
+    
+    private BatteryStats mStats;
+    private int mWhich = BatteryStats.STATS_UNPLUGGED;
+    private int mType = CPU_USAGE;
+    
+    private GraphableButton[] mButtons;
+    IBatteryStats mBatteryInfo;
+    
+    private List<CpuUsage> mCpuUsage = new ArrayList<CpuUsage>();
+    private List<NetworkUsage> mNetworkUsage = new ArrayList<NetworkUsage>();
+    private List<SensorUsage> mSensorUsage = new ArrayList<SensorUsage>();
+    private long mScreenOnTime;
+    
+    private LinearLayout mGraphLayout;
+    private LinearLayout mTextLayout;
+    private TextView mMessageText;
+    private TextView mDetailsText;
+    private Button mDetailsBackButton;
+    private Spinner mTypeSpinner;
+    private Spinner mWhichSpinner;
+    
+    private boolean mDetailsShown = false;
+    
+    private static String getLabel(String packageName, PackageManager pm) {
+        try {
+            ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
+            CharSequence label = ai.loadLabel(pm);
+            if (label != null) {
+                return label.toString();
+            }
+        } catch (NameNotFoundException e) {
+            return packageName;
+        }
+        
+        return "";
+    }
+    
+    void formatTime(double millis, StringBuilder sb) {
+        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));
+        }
+    }
+    
+    abstract class Graphable implements Comparable<Graphable> {        
+        protected String mName;
+        protected boolean mUniqueName;
+        protected String[] mPackageNames;
+        
+        public abstract String getLabel();
+        public abstract double getSortValue();
+        public abstract double[] getValues();
+        public abstract void getInfo(StringBuilder info);
+        
+        public int compareTo(Graphable o) {
+            double t = getSortValue();
+            double ot = o.getSortValue();
+            if (t < ot) {
+                // Largest first
+                return 1;
+            } else if (t > ot) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+                
+        // Side effects: sets mName and mUniqueName
+        void getNameForUid(int uid) {
+            PackageManager pm = getPackageManager();
+            mPackageNames = pm.getPackagesForUid(uid);
+            // Convert package names to user-facing labels where possible
+            for (int i = 0; i < mPackageNames.length; i++) {
+                mPackageNames[i] = BatteryHistory.getLabel(mPackageNames[i], pm);
+            }
+
+            if (mPackageNames.length == 1) {
+                mName = mPackageNames[0];
+                mUniqueName = true;
+            } else {
+                mName = getString(R.string.battery_history_uid, uid); // Default name
+                // If one of the names for this UID is in mKnownApps, use it
+                for (String name : mPackageNames) {
+                    if (mKnownApps.contains(name)) {
+                        mName = name;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    class CpuUsage extends Graphable {
+        double[] mUsage;
+        long mStarts;
+        
+        public CpuUsage(String name, long userTime, long systemTime, long starts) {
+            PackageManager pm = BatteryHistory.this.getPackageManager();
+            mName = BatteryHistory.getLabel(name, pm);
+            mUsage = new double[2];
+            
+            mUsage[0] = userTime;
+            mUsage[1] = userTime + systemTime;
+            mStarts = starts;
+        }
+        
+        public String getLabel() {
+            return mName;
+        }
+        
+        public double getSortValue() {
+            return mUsage[1];
+        }
+        
+        public double[] getValues() {
+            return mUsage;
+        }
+        
+        public void getInfo(StringBuilder info) {
+            info.append(getString(R.string.battery_history_cpu_usage, mName));
+            info.append("\n\n");
+            info.append(getString(R.string.battery_history_user_time));
+            formatTime(mUsage[0] * 10, info);
+            info.append('\n');
+            info.append(getString(R.string.battery_history_system_time));
+            formatTime((mUsage[1] - mUsage[0]) * 10, info);
+            info.append('\n');
+            info.append(getString(R.string.battery_history_total_time));
+            formatTime((mUsage[1]) * 10, info);
+            info.append('\n');
+            info.append(getString(R.string.battery_history_starts, mStarts));
+        }
+    }
+    
+    class NetworkUsage extends Graphable {
+        double[] mUsage;
+        
+        public NetworkUsage(int uid, long received, long sent) {
+            getNameForUid(uid);
+            
+            mUsage = new double[2];
+            mUsage[0] = received;
+            mUsage[1] = received + sent;
+        }
+        
+        public String getLabel() {
+            return mName;
+        }
+        
+        public double getSortValue() {
+            return mUsage[1];
+        }
+        
+        public double[] getValues() {
+            return mUsage;
+        }
+        
+        public void getInfo(StringBuilder info) {
+            info.append(getString(R.string.battery_history_network_usage, mName));
+            info.append("\n\n");
+            info.append(getString(R.string.battery_history_bytes_received, (long) mUsage[0]));
+            info.append('\n');
+            info.append(getString(R.string.battery_history_bytes_sent,
+                    (long) mUsage[1] - (long) mUsage[0]));
+            info.append('\n');
+            info.append(getString(R.string.battery_history_bytes_total, (long) mUsage[1]));
+
+            if (!mUniqueName) {
+                info.append("\n\n");
+                info.append(getString(R.string.battery_history_packages_sharing_this_uid));
+                info.append('\n');
+
+                PackageManager pm = BatteryHistory.this.getPackageManager();
+                List<String> names = new ArrayList<String>();
+                for (String name : mPackageNames) {
+                    names.add(BatteryHistory.getLabel(name, pm));
+                }
+                Collections.sort(names);
+                for (String name : names) {
+                    info.append("    ");
+                    info.append(name);
+                    info.append('\n');
+                }
+            }
+        }
+    }
+    
+    class SensorUsage extends Graphable {
+        int mSensorNumber;
+        double[] mUsage;
+        HashMap<Integer,Integer> mCounts;
+        
+        public SensorUsage(int sensorNumber, String sensorName, long totalTime,
+                HashMap<Integer,Integer> counts) {
+            mName = sensorName;
+            mSensorNumber = sensorNumber;
+            
+            mUsage = new double[1];
+            mUsage[0] = totalTime;
+            
+            mCounts = counts;
+        }
+        
+        public String getLabel() {
+            return mName;
+        }
+        
+        public double getSortValue() {
+            return mUsage[0];
+        }
+        
+        public double[] getValues() {
+            return mUsage;
+        }
+        
+        public void getInfo(StringBuilder info) {
+            info.append(getString(R.string.battery_history_sensor));
+            info.append(mName);
+            info.append("\n\n");
+            info.append(getString(R.string.battery_history_total_time));
+            formatTime(mUsage[0], info);
+            info.append("\n\n");
+            
+            PackageManager pm = getPackageManager();
+            String[] packageNames = null;
+            for (Map.Entry<Integer,Integer> ent : mCounts.entrySet()) {
+                int uid = ent.getKey().intValue();
+                int count = ent.getValue().intValue();
+                packageNames = pm.getPackagesForUid(uid).clone();
+                
+                if (packageNames.length == 1) {
+                    info.append(getString(R.string.battery_history_sensor_usage,
+                            count, packageNames[0]));
+                } else {
+                    info.append(getString(R.string.battery_history_sensor_usage_multi, count));
+                    info.append("\n");
+                    // Convert package names to user-facing labels where possible
+                    for (int i = 0; i < packageNames.length; i++) {
+                        info.append("    ");
+                        info.append(BatteryHistory.getLabel(packageNames[i], pm));
+                        info.append("\n");
+                    }
+                }
+            }
+        }
+    }
+    
+    private List<? extends Graphable> getGraphRecords() {
+        switch (mType) {
+            case CPU_USAGE: return mCpuUsage;
+            case NETWORK_USAGE : return mNetworkUsage;
+            case SENSOR_USAGE: return mSensorUsage;
+            case SCREEN_ON: return null;
+            case WAKE_LOCKS:
+            default:
+                return (List<? extends Graphable>) null; // TODO
+        }
+    }
+    
+    private void displayScreenUsage() {
+        mMessageText.setVisibility(View.VISIBLE);
+        StringBuilder sb = new StringBuilder();
+        sb.append(getString(R.string.battery_history_screen_on));
+        sb.append("\n\n");
+        sb.append(getString(R.string.battery_history_screen_on_battery));
+        sb.append(' ');
+        formatTime((double) mStats.getBatteryScreenOnTime(), sb);
+        sb.append('\n');
+        sb.append(getString(R.string.battery_history_screen_on_plugged));
+        sb.append(' ');
+        formatTime((double) mStats.getPluggedScreenOnTime(), sb);
+        sb.append('\n');
+        mMessageText.setText(sb.toString());
+    }
+    
+    private void displayGraph() {
+        Log.i(TAG, "displayGraph");
+
+        // Hide the UI and selectively enable it below
+        mMessageText.setVisibility(View.GONE);
+        for (int i = 0; i < mButtons.length; i++) {
+            mButtons[i].setVisibility(View.INVISIBLE);
+        }
+        
+        if (mType == SCREEN_ON) {
+            displayScreenUsage();
+            return;
+        }
+        
+        double maxValue = -Double.MAX_VALUE;
+        
+        List<? extends Graphable> records = getGraphRecords();
+        for (Graphable g : records) {
+            double[] values = g.getValues();
+            maxValue = Math.max(maxValue, values[values.length - 1]);
+        }
+        
+        int[] colors = new int[2];
+        colors[0] = 0xff0000ff;
+        colors[1] = 0xffff0000;
+        
+        for (int i = 0; i < mButtons.length; i++) {
+            mButtons[i].setVisibility(View.INVISIBLE);
+        }
+        
+        int numRecords = Math.min(records.size(), mButtons.length);
+        if (numRecords == 0) {
+             mMessageText.setVisibility(View.VISIBLE);
+             mMessageText.setText(R.string.battery_history_no_data);
+        } else {
+            for (int i = 0; i < numRecords; i++) {
+                Graphable r = records.get(i);           
+
+                mButtons[i].setText(r.getLabel());
+                mButtons[i].setValues(r.getValues(), maxValue);
+                mButtons[i].setVisibility(View.VISIBLE);
+            }
+        }
+    }
+    
+    private void hideDetails() {
+        mTextLayout.setVisibility(View.GONE);
+        mGraphLayout.setVisibility(View.VISIBLE);
+        mDetailsShown = false;
+    }
+    
+    private void showDetails(int id) {
+        mGraphLayout.setVisibility(View.GONE);
+        mTextLayout.setVisibility(View.VISIBLE);
+            
+        StringBuilder info = new StringBuilder();
+        List<? extends Graphable> records = getGraphRecords();
+        if (id < records.size()) {
+            Graphable record = records.get(id);
+            record.getInfo(info);
+        } else {
+            info.append(getString(R.string.battery_history_details_for, id));
+        }
+        mDetailsText.setText(info.toString());
+        mDetailsShown = true;
+    }
+
+    private void processCpuUsage() {
+        mCpuUsage.clear();
+        
+        SparseArray<? extends Uid> uidStats = mStats.getUidStats();
+        final int NU = uidStats.size();
+        for (int iu = 0; iu < NU; iu++) {
+            Uid u = uidStats.valueAt(iu);
+
+            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+            if (processStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+                        : processStats.entrySet()) {
+
+                    Uid.Proc ps = ent.getValue();
+                    long userTime = ps.getUserTime(mWhich);
+                    long systemTime = ps.getSystemTime(mWhich);
+                    long starts = ps.getStarts(mWhich);
+
+                    if (userTime != 0 || systemTime != 0) {
+                        mCpuUsage.add(new CpuUsage(ent.getKey(), userTime, systemTime, starts));
+                    }
+                }
+            }
+        }
+        Collections.sort(mCpuUsage);
+    }
+    
+    private void processNetworkUsage() {
+        mNetworkUsage.clear();
+        
+        SparseArray<? extends Uid> uidStats = mStats.getUidStats();
+        final int NU = uidStats.size();
+        for (int iu = 0; iu < NU; iu++) {
+            Uid u = uidStats.valueAt(iu);
+            
+            long received = u.getTcpBytesReceived(mWhich);
+            long sent = u.getTcpBytesSent(mWhich);
+            if (received + sent > 0) {
+                mNetworkUsage.add(new NetworkUsage(u.getUid(), received, sent));
+            }
+        }
+        Collections.sort(mNetworkUsage);
+    }
+    
+    class SensorRecord {
+        String name;
+        long totalTime;
+        HashMap<Integer,Integer> counts = new HashMap<Integer,Integer>();
+    }
+    
+    private void processSensorUsage() {
+        mSensorUsage.clear();
+        
+        HashMap<Integer,SensorRecord> records = new HashMap<Integer,SensorRecord>();
+        
+        long uSecTime = SystemClock.elapsedRealtime() * 1000;
+        final long uSecNow = mStats.getBatteryUptime(uSecTime);
+        
+        SparseArray<? extends Uid> uidStats = mStats.getUidStats();
+        final int NU = uidStats.size();
+        for (int iu = 0; iu < NU; iu++) {
+            Uid u = uidStats.valueAt(iu);
+            int uid = u.getUid();
+            
+            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+            if (sensorStats.size() > 0) {
+                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
+                        : sensorStats.entrySet()) {
+
+                    Uid.Sensor se = ent.getValue();
+                    String name = se.getName();
+                    int sensorNumber = ent.getKey();
+                    Timer timer = se.getSensorTime();
+                    if (timer != null) {
+                        // Convert from microseconds to milliseconds with rounding
+                        long totalTime = (timer.getTotalTime(uSecNow, mWhich) + 500) / 1000;
+                        int count = timer.getCount(mWhich);
+                        
+                        SensorRecord record = records.get(sensorNumber);
+                        if (record == null) {
+                            record = new SensorRecord();
+                        }
+                        record.name = name;
+                        record.totalTime += totalTime;
+                        Integer c = record.counts.get(uid);
+                        if (c == null) {
+                            record.counts.put(uid, count);
+                        } else {
+                            record.counts.put(uid, c.intValue() + count);
+                        }
+                        records.put(sensorNumber, record);
+                    }
+                }
+            }
+        }
+        
+        for (Map.Entry<Integer,SensorRecord> record : records.entrySet()) {
+            int sensorNumber = record.getKey().intValue();
+            SensorRecord r = record.getValue();
+            mSensorUsage.add(new SensorUsage(sensorNumber, r.name, r.totalTime, r.counts));
+        }
+        Collections.sort(mSensorUsage);
+    }
+    
+    private void processScreenOn() {
+        // Do nothing
+    }
+    
+    private void collectStatistics() {
+        processCpuUsage();
+        processNetworkUsage();
+        processSensorUsage();
+        processScreenOn();
+    }
+    
+    private void refresh() {
+        try {
+            mStats = mBatteryInfo.getStatistics();
+            collectStatistics();
+            displayGraph();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException:", e);
+        }
+    }
+    
+    public void onClick(View v) {
+        if (v == mDetailsBackButton) {
+            hideDetails();
+            return;
+        }
+        
+        int id = ((Integer) v.getTag()).intValue();
+        showDetails(id);
+    }
+    
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK && mDetailsShown) {
+            hideDetails();
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+        if (parent.equals(mTypeSpinner)) {
+            mType = position;
+            switch (position) {
+                case CPU_USAGE:
+                    mWhichSpinner.setEnabled(true);
+                    break;
+                case NETWORK_USAGE:
+                    mWhichSpinner.setEnabled(true);
+                    break;
+                case SENSOR_USAGE:
+                    mWhichSpinner.setEnabled(true);
+                    break;
+                case SCREEN_ON:
+                    mWhichSpinner.setEnabled(false);
+                    break;
+                case WAKE_LOCKS:
+                    break;
+            }
+        } else if (parent.equals(mWhichSpinner)) {
+            mWhich = position;
+        }
+        
+        refresh();
+    }
+
+    public void onNothingSelected(AdapterView<?> parent) {
+        // Do nothing
+    }
+    
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "onCreate");
+        
+        String knownApps = getString(R.string.battery_history_known_apps);
+        String[] knownAppNames = knownApps.split(";");
+        for (String name : knownAppNames) {
+            mKnownApps.add(name);
+        }
+        
+        setContentView(R.layout.battery_history);
+        
+        mGraphLayout = (LinearLayout) findViewById(R.id.graphLayout);
+        mTextLayout = (LinearLayout) findViewById(R.id.textLayout);
+        mDetailsText = (TextView) findViewById(R.id.detailsText);
+        mMessageText = (TextView) findViewById(R.id.messageText);
+        
+        mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner);
+        mTypeSpinner.setOnItemSelectedListener(this);
+        
+        mWhichSpinner = (Spinner) findViewById(R.id.whichSpinner);
+        mWhichSpinner.setOnItemSelectedListener(this);
+        
+        mButtons = new GraphableButton[8];
+        mButtons[0] = (GraphableButton) findViewById(R.id.button0);
+        mButtons[1] = (GraphableButton) findViewById(R.id.button1);
+        mButtons[2] = (GraphableButton) findViewById(R.id.button2);
+        mButtons[3] = (GraphableButton) findViewById(R.id.button3);
+        mButtons[4] = (GraphableButton) findViewById(R.id.button4);
+        mButtons[5] = (GraphableButton) findViewById(R.id.button5);
+        mButtons[6] = (GraphableButton) findViewById(R.id.button6);
+        mButtons[7] = (GraphableButton) findViewById(R.id.button7);
+        
+        for (int i = 0; i < mButtons.length; i++) {
+            mButtons[i].setTag(i);
+            mButtons[i].setOnClickListener(this);
+        }
+        
+        mBatteryInfo = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+        refresh();
+    }
+}
diff --git a/src/com/android/settings/battery_history/GraphableButton.java b/src/com/android/settings/battery_history/GraphableButton.java
new file mode 100644
index 0000000..39028d0
--- /dev/null
+++ b/src/com/android/settings/battery_history/GraphableButton.java
@@ -0,0 +1,55 @@
+package com.android.settings.battery_history;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.Button;
+
+public class GraphableButton extends Button {
+    private static final String TAG = "GraphableButton";
+
+    static Paint[] sPaint = new Paint[2];
+    static {
+        sPaint[0] = new Paint();
+        sPaint[0].setStyle(Paint.Style.FILL);
+        sPaint[0].setColor(Color.BLUE);
+        
+        sPaint[1] = new Paint();
+        sPaint[1].setStyle(Paint.Style.FILL);
+        sPaint[1].setColor(Color.RED);
+    }
+    
+    double[] mValues;
+    
+    public GraphableButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+    
+    public void setValues(double[] values, double maxValue) {
+        mValues = values.clone();
+        for (int i = 0; i < values.length; i++) {
+            mValues[i] /= maxValue;
+        }
+    }
+    
+    @Override
+    public void onDraw(Canvas canvas) {
+        Log.i(TAG, "onDraw: w = " + getWidth() + ", h = " + getHeight());
+        
+        int xmin = getPaddingLeft();
+        int xmax = getWidth() - getPaddingRight();
+        int ymin = getPaddingTop();
+        int ymax = getHeight() - getPaddingBottom();
+        
+        int startx = xmin;
+        for (int i = 0; i < mValues.length; i++) {
+            int endx = xmin + (int) (mValues[i] * (xmax - xmin));
+            canvas.drawRect(startx, ymin, endx, ymax, sPaint[i]);
+            startx = endx;
+        }
+        super.onDraw(canvas);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
index facb763..a51f9b5e 100644
--- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
@@ -19,6 +19,7 @@
 import com.android.settings.R;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -56,14 +57,12 @@
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            /*
-             * TODO: remove this once the BT framework broadcasts the
-             * MODE_CHANGED action when going into MODE_OFF.
-             */
-            int mode = BluetoothIntent.DISABLED_ACTION.equals(intent.getAction())
-                    ? BluetoothDevice.MODE_OFF                    
-                    : intent.getIntExtra(BluetoothIntent.MODE, BluetoothDevice.MODE_UNKNOWN);
-            handleModeChanged(mode);
+            if (BluetoothIntent.SCAN_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+                int mode = intent.getIntExtra(BluetoothIntent.SCAN_MODE, BluetoothError.ERROR);
+                if (mode != BluetoothError.ERROR) {
+                    handleModeChanged(mode);
+                }
+            }
         }
     };
 
@@ -92,12 +91,12 @@
             return;
         }
 
-        IntentFilter filter = new IntentFilter(BluetoothIntent.MODE_CHANGED_ACTION);
+        IntentFilter filter = new IntentFilter(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
         filter.addAction(BluetoothIntent.DISABLED_ACTION);
         mContext.registerReceiver(mReceiver, filter);
         mCheckBoxPreference.setOnPreferenceChangeListener(this);
         
-        handleModeChanged(mLocalManager.getBluetoothManager().getMode());
+        handleModeChanged(mLocalManager.getBluetoothManager().getScanMode());
     }
     
     public void pause() {
@@ -132,11 +131,9 @@
             long endTimestamp = System.currentTimeMillis() + timeout * 1000;
             persistDiscoverableEndTimestamp(endTimestamp);
             
-            manager.setMode(BluetoothDevice.MODE_DISCOVERABLE);
-            handleModeChanged(BluetoothDevice.MODE_DISCOVERABLE);            
-            
+            manager.setScanMode(BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
         } else {
-            manager.setMode(BluetoothDevice.MODE_CONNECTABLE);
+            manager.setScanMode(BluetoothDevice.SCAN_MODE_CONNECTABLE);
         }
     }
 
@@ -160,7 +157,7 @@
             Log.v(TAG, "Got mode changed: " + mode);
         }
         
-        if (mode == BluetoothDevice.MODE_DISCOVERABLE) {
+        if (mode == BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
             mCheckBoxPreference.setChecked(true);
             updateCountdownSummary();
             
@@ -170,8 +167,8 @@
     }
     
     private void updateCountdownSummary() {
-        int mode = mLocalManager.getBluetoothManager().getMode();
-        if (mode != BluetoothDevice.MODE_DISCOVERABLE) {
+        int mode = mLocalManager.getBluetoothManager().getScanMode();
+        if (mode != BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
             return;
         }
             
diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
index fe64d13..a588013 100644
--- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
+++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
@@ -52,31 +52,39 @@
                 
             if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
                 mManager.setBluetoothStateInt(ExtendedBluetoothState.ENABLED);
+                
             } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
                 mManager.setBluetoothStateInt(ExtendedBluetoothState.DISABLED);
                     
             } else if (action.equals(BluetoothIntent.DISCOVERY_STARTED_ACTION)) {
                 mManager.onScanningStateChanged(true);
+                
             } else if (action.equals(BluetoothIntent.DISCOVERY_COMPLETED_ACTION)) {
                 mManager.onScanningStateChanged(false);
                     
             } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION)) {
                 short rssi = intent.getShortExtra(BluetoothIntent.RSSI, Short.MIN_VALUE);
                 mManager.getLocalDeviceManager().onDeviceAppeared(address, rssi);
+                
             } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION)) {
                 mManager.getLocalDeviceManager().onDeviceDisappeared(address);
+                
             } else if (action.equals(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION)) {
                 mManager.getLocalDeviceManager().onDeviceNameUpdated(address);
+                
             } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) {
                 int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE,
                                                    BluetoothError.ERROR);
                 mManager.getLocalDeviceManager().onBondingStateChanged(address, bondState);
                 if (bondState == BluetoothDevice.BOND_NOT_BONDED) {
                     int reason = intent.getIntExtra(BluetoothIntent.REASON, BluetoothError.ERROR);
-                    Log.w(TAG, address + " unbonded with reason " + reason +
-                          ", TODO: handle this nicely in the UI");  //TODO
-                    mManager.getLocalDeviceManager().onBondingError(address);
+                    if (reason == BluetoothDevice.UNBOND_REASON_AUTH_FAILED ||
+                            reason == BluetoothDevice.UNBOND_REASON_AUTH_REJECTED ||
+                            reason == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN) {
+                        mManager.getLocalDeviceManager().onBondingError(address, reason);
+                    }
                 }
+                
             } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
                 mManager.getLocalDeviceManager().onProfileStateChanged(address);
 
@@ -96,6 +104,10 @@
                         oldState == BluetoothA2dp.STATE_CONNECTING) {
                     mManager.getLocalDeviceManager().onConnectingError(address);
                 }
+                
+            } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION)) {
+                mManager.getLocalDeviceManager().onBtClassChanged(address);
+                
             }
         }
     };
@@ -124,6 +136,7 @@
         // Fine-grained state broadcasts
         filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
         filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
+        filter.addAction(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
         
         mManager.getContext().registerReceiver(mBroadcastReceiver, filter);
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothPinDialog.java b/src/com/android/settings/bluetooth/BluetoothPinDialog.java
index 291d0c1..a8e7737 100644
--- a/src/com/android/settings/bluetooth/BluetoothPinDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPinDialog.java
@@ -18,13 +18,19 @@
 
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
+import android.text.Editable;
 import android.text.InputFilter;
-import android.text.method.DigitsKeyListener;
+import android.text.TextWatcher;
+import android.text.InputFilter.LengthFilter;
 import android.util.Log;
 import android.view.View;
+import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;
 
@@ -36,12 +42,31 @@
  * BluetoothPinDialog asks the user to enter a PIN for pairing with a remote
  * Bluetooth device. It is an activity that appears as a dialog.
  */
-public class BluetoothPinDialog extends AlertActivity implements DialogInterface.OnClickListener {
+public class BluetoothPinDialog extends AlertActivity implements DialogInterface.OnClickListener,
+        TextWatcher {
     private static final String TAG = "BluetoothPinDialog";
 
     private LocalBluetoothManager mLocalManager;
     private String mAddress;
     private EditText mPinView;
+    private Button mOkButton;
+
+    private static final String INSTANCE_KEY_PAIRING_CANCELED = "received_pairing_canceled";
+    private boolean mReceivedPairingCanceled;
+    
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!BluetoothIntent.PAIRING_CANCEL_ACTION.equals(intent.getAction())) {
+                return;
+            }
+            
+            String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
+            if (address == null || address.equals(mAddress)) {
+                onReceivedPairingCanceled();
+            }
+        }
+    };
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -69,6 +94,39 @@
         p.mNegativeButtonText = getString(android.R.string.cancel);
         p.mNegativeButtonListener = this;
         setupAlert();
+        
+        mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
+        mOkButton.setEnabled(false);
+
+        /*
+         * Leave this registered through pause/resume since we still want to
+         * finish the activity in the background if pairing is canceled.
+         */
+        registerReceiver(mReceiver, new IntentFilter(BluetoothIntent.PAIRING_CANCEL_ACTION));
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        
+        mReceivedPairingCanceled = savedInstanceState.getBoolean(INSTANCE_KEY_PAIRING_CANCELED);
+        if (mReceivedPairingCanceled) {
+            onReceivedPairingCanceled();
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        
+        outState.putBoolean(INSTANCE_KEY_PAIRING_CANCELED, mReceivedPairingCanceled);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        
+        unregisterReceiver(mReceiver);
     }
 
     private View createView() {
@@ -79,9 +137,32 @@
         messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name));
         
         mPinView = (EditText) view.findViewById(R.id.text);
+        mPinView.addTextChangedListener(this);
+        // Maximum of 10 characters in a PIN
+        mPinView.setFilters(new InputFilter[] { new LengthFilter(10) });
         
         return view;
     }
+
+    public void afterTextChanged(Editable s) {
+        if (s.length() > 0) {
+            mOkButton.setEnabled(true);
+        }
+    }
+
+    private void onReceivedPairingCanceled() {
+        mReceivedPairingCanceled = true;
+        
+        TextView messageView = (TextView) findViewById(R.id.message);
+        messageView.setText(getString(R.string.bluetooth_pairing_error_message,
+                mLocalManager.getLocalDeviceManager().getName(mAddress)));
+        
+        mPinView.setEnabled(false);
+        mPinView.clearFocus();
+        mPinView.removeTextChangedListener(this);
+        
+        mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
+    }
     
     private void onPair(String pin) {
         byte[] pinBytes = BluetoothDevice.convertPinToBytes(pin);
@@ -94,7 +175,7 @@
     }
 
     private void onCancel() {
-        mLocalManager.getBluetoothManager().cancelPin(mAddress);
+        mLocalManager.getBluetoothManager().cancelBondProcess(mAddress);
     }
     
     public void onClick(DialogInterface dialog, int which) {
@@ -109,4 +190,12 @@
         }
     }
 
+    /* Not used */
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    /* Not used */
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+    }
+
 }
diff --git a/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java b/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java
index 23a43bd..f2f3bdf 100644
--- a/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java
+++ b/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java
@@ -25,10 +25,7 @@
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
 import android.text.TextUtils;
-import android.widget.ImageView;
-import android.widget.TextView;
 import android.util.Log;
 
 /**
@@ -114,7 +111,7 @@
         mManager.setForegroundActivity(this);
         mDevice.registerCallback(this);
 
-        refresh(true);
+        refresh();
     }
 
     @Override
@@ -169,7 +166,7 @@
     }
 
     private void onOnlineModeCheckedStateChanged(boolean checked) {
-        switchModes(checked, false);
+        setOnlineMode(checked, true);
     }
     
     private void onProfileCheckedStateChanged(Profile profile, boolean checked) {
@@ -187,39 +184,34 @@
     }
     
     public void onDeviceAttributesChanged(LocalBluetoothDevice device) {
-        refresh(false);
+        refresh();
     }
 
-    private void refresh(boolean forceRefresh) {
-        // The online mode could have changed
-        updateOnlineMode(forceRefresh);
+    private void refresh() {
+        // We are in 'online mode' if we are connected, connecting, or disconnecting
+        setOnlineMode(mDevice.isConnected() || mDevice.isBusy(), false);
         refreshProfiles();
-        refreshOnlineModePreference();
     }
 
-    private void updateOnlineMode(boolean force) {
-        // Connected or Connecting (and Disconnecting, which is fine)
-        boolean onlineMode = mDevice.isConnected() || mDevice.isBusy();
-        switchModes(onlineMode, force);
-    }
-    
     /**
      * Switches between online/offline mode.
      * 
      * @param onlineMode Whether to be in online mode, or offline mode.
+     * @param takeAction Whether to take action (i.e., connect or disconnect)
+     *            based on the new online mode.
      */
-    private void switchModes(boolean onlineMode, boolean force) {
-        if (mOnlineMode != onlineMode || force) {
-            mOnlineMode = onlineMode;
+    private void setOnlineMode(boolean onlineMode, boolean takeAction) {
+        mOnlineMode = onlineMode;
             
+        if (takeAction) {
             if (onlineMode) {
                 mDevice.connect();
             } else {
                 mDevice.disconnect();
             }
-
-            refreshOnlineModePreference();
         }
+            
+        refreshOnlineModePreference();
     }
     
     private void refreshOnlineModePreference() {
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java
index 26ddbf2..009ba5e 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java
@@ -60,8 +60,6 @@
     
     private boolean mVisible;
     
-    private int mBondState;
-    
     private final LocalBluetoothManager mLocalManager;
     
     private List<Callback> mCallbacks = new ArrayList<Callback>();
@@ -144,6 +142,9 @@
     public void connect() {
         if (!ensurePaired()) return;
         
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+
         Context context = mLocalManager.getContext();
         boolean hasAtLeastOnePreferredProfile = false;
         for (Profile profile : mProfiles) {
@@ -151,7 +152,7 @@
                     LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
             if (profileManager.isPreferred(mAddress)) {
                 hasAtLeastOnePreferredProfile = true;
-                connect(profile);
+                connectInt(profile);
             }
         }
         
@@ -163,23 +164,31 @@
     private void connectAndPreferAllProfiles() {
         if (!ensurePaired()) return;
         
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+        
         Context context = mLocalManager.getContext();
         for (Profile profile : mProfiles) {
             LocalBluetoothProfileManager profileManager =
                     LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
             profileManager.setPreferred(mAddress, true);
-            connect(profile);
+            connectInt(profile);
         }
     }
     
     public void connect(Profile profile) {
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+        connectInt(profile);
+    }
+    
+    public void connectInt(Profile profile) {
         if (!ensurePaired()) return;
         
         LocalBluetoothProfileManager profileManager =
                 LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 
         int status = profileManager.getConnectionStatus(mAddress);
         if (!SettingsBtStatus.isConnectionStatusConnected(status)) {
-            mIsConnectingErrorPossible = true;
             if (profileManager.connect(mAddress) != BluetoothDevice.RESULT_SUCCESS) {
                 showConnectingError();
             }
@@ -211,9 +220,9 @@
             manager.cancelDiscovery();
         }
 
-        if (mLocalManager.createBonding(mAddress)) {
-            //TODO: consider removing this line - UI will update through Intent
-            setBondState(BluetoothDevice.BOND_BONDING);
+        if (!mLocalManager.getBluetoothManager().createBond(mAddress)) {
+            mLocalManager.showError(mAddress, R.string.bluetooth_error_title,
+                    R.string.bluetooth_pairing_error_message);
         }
     }
 
@@ -235,11 +244,7 @@
         BluetoothDevice manager = mLocalManager.getBluetoothManager();
 
         fetchName();
-        mBtClass = manager.getRemoteClass(mAddress);
-
-        LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
-
-        mBondState = manager.getBondState(mAddress);
+        fetchBtClass();
 
         mVisible = false;
 
@@ -283,14 +288,7 @@
     }
 
     public int getBondState() {
-        return mBondState;
-    }
-
-    void setBondState(int bondState) {
-        if (mBondState != bondState) {
-            mBondState = bondState;
-            dispatchAttributesChanged();
-        }
+        return mLocalManager.getBluetoothManager().getBondState(mAddress);
     }
 
     void setRssi(short rssi) {
@@ -355,6 +353,24 @@
         }
     }
 
+    /**
+     * Fetches a new value for the cached BT class.
+     */
+    private void fetchBtClass() {
+        mBtClass = mLocalManager.getBluetoothManager().getRemoteClass(mAddress);
+        mProfiles.clear();
+        LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
+    }
+
+    /**
+     * Refreshes the UI for the BT class, including fetching the latest value
+     * for the class.
+     */
+    public void refreshBtClass() {
+        fetchBtClass();
+        dispatchAttributesChanged();
+    }
+    
     public int getSummary() {
         // TODO: clean up
         int oneOffSummary = getOneOffSummary();
@@ -425,17 +441,15 @@
         // No context menu if it is busy (none of these items are applicable if busy)
         if (isBusy()) return;
         
-        // No context menu if there are no profiles
-        if (mProfiles.size() == 0) return;
-        
         int bondState = getBondState();
         boolean isConnected = isConnected();
+        boolean hasProfiles = mProfiles.size() > 0;
         
         menu.setHeaderTitle(getName());
         
         if (isConnected) {
             menu.add(0, CONTEXT_ITEM_DISCONNECT, 0, R.string.bluetooth_device_context_disconnect);
-        } else {
+        } else if (hasProfiles) {
             // For connection action, show either "Connect" or "Pair & connect"
             int connectString = (bondState == BluetoothDevice.BOND_NOT_BONDED)
                     ? R.string.bluetooth_device_context_pair_connect
@@ -538,8 +552,8 @@
         if (comparison != 0) return comparison;
         
         // Paired above not paired
-        comparison = (another.mBondState == BluetoothDevice.BOND_BONDED ? 1 : 0) -
-            (mBondState == BluetoothDevice.BOND_BONDED ? 1 : 0);
+        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
+            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
         if (comparison != 0) return comparison;
 
         // Visible above not visible
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java
index a751656..6bb2b4a 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java
@@ -45,19 +45,23 @@
         readPairedDevices();
     }
 
-    private synchronized void readPairedDevices() {
+    private synchronized boolean readPairedDevices() {
         BluetoothDevice manager = mLocalManager.getBluetoothManager();
         String[] bondedAddresses = manager.listBonds();
-        if (bondedAddresses == null) return;
+        if (bondedAddresses == null) return false;
         
+        boolean deviceAdded = false;
         for (String address : bondedAddresses) {
             LocalBluetoothDevice device = findDevice(address);
             if (device == null) {
                 device = new LocalBluetoothDevice(mLocalManager.getContext(), address);
                 mDevices.add(device);
-                dispatchDeviceAdded(device);                
+                dispatchDeviceAdded(device);
+                deviceAdded = true;
             }
         }
+        
+        return deviceAdded;
     }
     
     public synchronized List<LocalBluetoothDevice> getDevicesCopy() {
@@ -157,23 +161,33 @@
     public synchronized void onBondingStateChanged(String address, int bondState) {
         LocalBluetoothDevice device = findDevice(address);
         if (device == null) {
-            Log.e(TAG, "Got bonding state changed for " + address +
-                    ", but we have no record of that device.");
+            if (!readPairedDevices()) {
+                Log.e(TAG, "Got bonding state changed for " + address +
+                        ", but we have no record of that device.");
+            }
             return;
         }
 
-        device.setBondState(bondState);  //TODO: might be unecessary
-        checkForDeviceRemoval(device);
+        device.refresh();
 
         if (bondState == BluetoothDevice.BOND_BONDED) {
             // Auto-connect after pairing
             device.connect();
         }
     }
-    
-    public synchronized void onBondingError(String address) {
+
+    /**
+     * Called when there is a bonding error.
+     * 
+     * @param address The address of the remote device.
+     * @param reason The reason, one of the error reasons from
+     *            BluetoothDevice.UNBOND_REASON_*
+     */
+    public synchronized void onBondingError(String address, int reason) {
         mLocalManager.showError(address, R.string.bluetooth_error_title,
-                R.string.bluetooth_pairing_error_message);
+                (reason == BluetoothDevice.UNBOND_REASON_AUTH_FAILED) ?
+                        R.string.bluetooth_pairing_pin_error_message :
+                        R.string.bluetooth_pairing_error_message);
     }
     
     public synchronized void onProfileStateChanged(String address) {
@@ -205,4 +219,11 @@
             checkForDeviceRemoval(device);
         }
     }
+    
+    public synchronized void onBtClassChanged(String address) {
+        LocalBluetoothDevice device = findDevice(address);
+        if (device != null) {
+            device.refreshBtClass();
+        }
+    }
 }
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
index f8275b5..4fd708e 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
@@ -226,10 +226,6 @@
         }
     }
 
-    public boolean createBonding(String address) {
-        return mManager.createBond(address);
-    }
-    
     public void showError(String address, int titleResId, int messageResId) {
         LocalBluetoothDevice device = mLocalDeviceManager.findDevice(address);
         if (device == null) return;
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index 86e6423..adfe88c 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -48,11 +48,13 @@
 
     private static final String MEMORY_SD_UNMOUNT = "memory_sd_unmount";
 
+    private static final String MEMORY_SD_FORMAT = "memory_sd_format";
     private Resources mRes;
 
     private Preference mSdSize;
     private Preference mSdAvail;
     private Preference mSdUnmount;
+    private Preference mSdFormat;
     
     // Access using getMountService()
     private IMountService mMountService = null;
@@ -67,6 +69,7 @@
         mSdSize = findPreference(MEMORY_SD_SIZE);
         mSdAvail = findPreference(MEMORY_SD_AVAIL);
         mSdUnmount = findPreference(MEMORY_SD_UNMOUNT);
+        mSdFormat = findPreference(MEMORY_SD_FORMAT);
     }
     
     @Override
@@ -109,6 +112,11 @@
         if (preference == mSdUnmount) {
             unmount();
             return true;
+        } else if (preference == mSdFormat) {
+            Intent intent = new Intent(Intent.ACTION_VIEW);
+            intent.setClass(this, com.android.settings.MediaFormat.class);
+            startActivity(intent);
+            return true;
         }
         
         return false;
@@ -134,7 +142,7 @@
             updateMemoryStatus();
         }
     }
-    
+
     private void updateMemoryStatus() {
         String status = Environment.getExternalStorageState();
         String readOnly = "";
@@ -143,6 +151,8 @@
             readOnly = mRes.getString(R.string.read_only);
         }
  
+        mSdFormat.setEnabled(false);
+
         if (status.equals(Environment.MEDIA_MOUNTED)) {
             try {
                 File path = Environment.getExternalStorageDirectory();
@@ -164,6 +174,14 @@
             mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
             mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
             mSdUnmount.setEnabled(false);
+
+            if (status.equals(Environment.MEDIA_UNMOUNTED) ||
+                status.equals(Environment.MEDIA_NOFS) ||
+                status.equals(Environment.MEDIA_UNMOUNTABLE) ) {
+                mSdFormat.setEnabled(true);
+            }
+
+            
         }
 
         File path = Environment.getDataDirectory();
diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java
index b7aceb1..98aa12b 100644
--- a/src/com/android/settings/deviceinfo/Status.java
+++ b/src/com/android/settings/deviceinfo/Status.java
@@ -30,6 +30,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.NetStat;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.telephony.PhoneStateListener;
@@ -64,10 +65,11 @@
 
     private static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address";
     private static final String KEY_BT_ADDRESS = "bt_address";
+    private static final String KEY_NETWORK_TRAFFIC_STATS = "network_traffic_stats";
     private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200;
     private static final int EVENT_SERVICE_STATE_CHANGED = 300;
-    
-    private static final int EVENT_FIX_UPTIME = 500;
+
+    private static final int EVENT_UPDATE_STATS = 500;
 
     private TelephonyManager mTelephonyManager;
     private Phone mPhone = null;
@@ -108,9 +110,10 @@
                     status.updateServiceState(serviceState);
                     break;
 
-                case EVENT_FIX_UPTIME:
+                case EVENT_UPDATE_STATS:
                     status.updateTimes();
-                    sendMessageDelayed(obtainMessage(EVENT_FIX_UPTIME), 1000);
+                    status.setNetworkTrafficStats();
+                    sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000);
                     break;
             }
         }
@@ -196,7 +199,7 @@
         
         setWifiStatus();
         setBtStatus();
-    }   
+    }
     
     @Override
     protected void onResume() {
@@ -212,7 +215,7 @@
         mTelephonyManager.listen(mPhoneStateListener,
                   PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
 
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_FIX_UPTIME), 0);
+        mHandler.sendEmptyMessage(EVENT_UPDATE_STATS);
     }
     
     @Override
@@ -222,7 +225,7 @@
         mPhoneStateReceiver.unregisterIntent();
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
         unregisterReceiver(mBatteryInfoReceiver);
-        mHandler.removeMessages(EVENT_FIX_UPTIME);
+        mHandler.removeMessages(EVENT_UPDATE_STATS);
     }
 
     /**
@@ -349,6 +352,17 @@
         }
     }
 
+    private void setNetworkTrafficStats() {
+        long txPkts = NetStat.getTotalTxPkts();
+        long txBytes = NetStat.getTotalTxBytes();
+        long rxPkts = NetStat.getTotalRxPkts();
+        long rxBytes = NetStat.getTotalRxBytes();
+
+        Preference netStatsPref = findPreference(KEY_NETWORK_TRAFFIC_STATS);
+        netStatsPref.setSummary(getString(R.string.status_network_traffic_summary,
+                txPkts, txBytes, rxPkts, rxBytes));
+    }
+
     void updateTimes() {
         long at = SystemClock.uptimeMillis() / 1000;
         long ut = SystemClock.elapsedRealtime() / 1000;
diff --git a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java
index 2ec685d..4d44524 100644
--- a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java
+++ b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java
@@ -16,8 +16,6 @@
 
 package com.android.settings.quicklaunch;
 
-import com.android.settings.R;
-
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
@@ -28,10 +26,9 @@
 import android.os.Handler;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 import android.provider.Settings.Bookmarks;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -40,6 +37,8 @@
 import android.view.View;
 import android.widget.AdapterView;
 
+import com.android.settings.R;
+
 /**
  * Settings activity for quick launch.
  * <p>
@@ -76,7 +75,7 @@
     private SparseBooleanArray mBookmarkedShortcuts;
     
     /** Preference category to hold the shortcut preferences. */
-    private PreferenceCategory mShortcutCategory;
+    private PreferenceGroup mShortcutGroup;
     /** Mapping of a shortcut to its preference. */
     private SparseArray<ShortcutPreference> mShortcutToPreference;
 
@@ -93,7 +92,7 @@
         
         addPreferencesFromResource(R.xml.quick_launch_settings);
         
-        mShortcutCategory = (PreferenceCategory) findPreference(KEY_SHORTCUT_CATEGORY);
+        mShortcutGroup = (PreferenceGroup) findPreference(KEY_SHORTCUT_CATEGORY);
         mShortcutToPreference = new SparseArray<ShortcutPreference>();
         mBookmarksObserver = new BookmarksObserver(mUiHandler);
         initShortcutPreferences();
@@ -252,7 +251,7 @@
     
     private ShortcutPreference createPreference(char shortcut) {
         ShortcutPreference pref = new ShortcutPreference(QuickLaunchSettings.this, shortcut);
-        mShortcutCategory.addPreference(pref);
+        mShortcutGroup.addPreference(pref);
         mShortcutToPreference.put(shortcut, pref);
         return pref;
     }