Merge "Fix strings" into jb-mr1-dev
diff --git a/res/drawable/regulatory_info.png b/res/drawable/regulatory_info.png
new file mode 100644
index 0000000..65de26c
--- /dev/null
+++ b/res/drawable/regulatory_info.png
Binary files differ
diff --git a/res/layout/regulatory_info.xml b/res/layout/regulatory_info.xml
new file mode 100755
index 0000000..e4999a4
--- /dev/null
+++ b/res/layout/regulatory_info.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:src="@drawable/regulatory_info"/>
diff --git a/res/values/bools.xml b/res/values/bools.xml
index 23bdf0d..ba402e5 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -32,4 +32,7 @@
 
     <!-- Whether User management screen is available -->
     <bool name="enable_user_management">false</bool>
+
+    <!-- Whether to show a preference item for regulatory information in About phone -->
+    <bool name="config_show_regulatory_info">false</bool>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 48af683..00adeba 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2235,6 +2235,8 @@
     <string name="legal_information">Legal information</string>
     <!-- About phone settings screen, setting option name to see a list of contributors -->
     <string name="contributors_title">Contributors</string>
+    <!-- About phone settings screen, setting option name to show regulatory information [CHAR LIMIT=25] -->
+    <string name="regulatory_information">Regulatory information</string>
     <!-- Note: this may be replaced by a more-specific title of the activity that will get launched --> <skip />
     <!-- About phone settings screen, setting option name to see copyright-related info -->
     <string name="copyright_title">Copyright</string>
@@ -2436,6 +2438,8 @@
     <string name="external_data_size_label" product="default">SD card</string>
     <!-- Manage applications, individual application info screen, button label under Storage heading. Button to remove the application from the system. -->
     <string name="uninstall_text">Uninstall</string>
+    <!-- Manage applications, individual application info screen, menu item to uninstall an application for all users. -->
+    <string name="uninstall_all_users_text">Uninstall for all users</string>
     <!-- [CHAR LIMIT=NONE] Manage applications, individual application info screen, button label under Storage heading. Button to install an application for the user. -->
     <string name="install_text">Install</string>
     <!-- [CHAR LIMIT=25] Manage applications, individual application info screen, button label under Storage heading. Button to disable an existing application. -->
@@ -2507,6 +2511,8 @@
     <string name="filter_apps_onsdcard" product="default">On SD card</string>
     <!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
     <string name="disabled">Disabled</string>
+    <!-- [CHAR LIMIT=25] Manage applications, text telling using an application is not installed. -->
+    <string name="not_installed">Not installed</string>
     <!-- [CHAR LIMIT=25] Text shown when there are no applications to display. -->
     <string name="no_applications">No apps.</string>
     <!-- [CHAR LIMIT=15] Manage applications, label for chart showing internal storage use. -->
@@ -4185,6 +4191,8 @@
     <string name="user_summary_active">Active</string>
     <!-- User summary to indicate that user is currently inactive in the background [CHAR LIMIT=100] -->
     <string name="user_summary_inactive">Not active</string>
+    <!-- User summary to indicate that user is currently not set up [CHAR LIMIT=100] -->
+    <string name="user_summary_not_set_up">Not set up</string>
     <!-- User information string to represent the owner of the device [CHAR LIMIT=25] -->
     <string name="user_owner">Owner</string>
     <!-- Title for the preference to enter the nickname of the userto display in the user switcher [CHAR LIMIT=25]-->
@@ -4192,14 +4200,26 @@
     <!-- Title for add user confirmation dialog [CHAR LIMIT=30] -->
     <string name="user_add_user_title">Add new user</string>
     <!-- Message for add user confirmation dialog [CHAR LIMIT=none] -->
-    <string name="user_add_user_message">Adding a user to this device will take them through guided setup.\n\nEach user will have their own apps and personal space on this device.\nUsers can accept permissions for updates on behalf of other users of this device.\nYou can switch between users on the lock screen.</string>
+    <string name="user_add_user_message">Each user you add can go to their own space from the lock screen and perform most routine tasks such as installing, updating, or uninstalling apps. After you create a new user, that person needs to go through a setup process.</string>
+    <!-- Title of dialog to setup a new user [CHAR LIMIT=30] -->
+    <string name="user_setup_dialog_title">Set up user now?</string>
+    <!-- Message in dialog to setup a new user after creation [CHAR LIMIT=none] -->
+    <string name="user_setup_dialog_message">Make sure the person is available to take the tablet and set up their space</string>
+    <!-- Button text to setup the new user now [CHAR LIMIT=25] -->
+    <string name="user_setup_button_setup_now">Set up now</string>
+    <!-- Button text to setup the new user later [CHAR LIMIT=25] -->
+    <string name="user_setup_button_setup_later">Not now</string>
 
     <!-- User details remove user menu [CHAR LIMIT=20] -->
     <string name="user_remove_user_menu">Remove user</string>
     <!-- User details new user name [CHAR LIMIT=30] -->
     <string name="user_new_user_name">New user</string>
+    <!-- User (self) removal confirmation title [CHAR LIMIT=30] -->
+    <string name="user_confirm_remove_self_title">Delete yourself?</string>
     <!-- User removal confirmation title [CHAR LIMIT=25] -->
     <string name="user_confirm_remove_title">Remove user?</string>
+    <!-- User (self) removal confirmation message [CHAR LIMIT=none] -->
+    <string name="user_confirm_remove_self_message">You will lose your space and data on this delete. Are you sure you want to remove the user and all associated data from the device?</string>
     <!-- User removal confirmation message [CHAR LIMIT=none] -->
     <string name="user_confirm_remove_message">Are you sure you want to remove the user and all associated data from the device?</string>
     <!-- Setting label to show that a new user is being added [CHAR LIMIT=30] -->
@@ -4237,6 +4257,10 @@
     <string name="help_url_tether" translatable="false"></string>
     <!-- Help URL, Dreams [DO NOT TRANSLATE] -->
     <string name="help_url_dreams" translatable="false"></string>
+    <!-- Help URL, User settings [DO NOT TRANSLATE] -->
+    <string name="help_url_users" translatable="false"></string>
+    <!-- Help URL, Location access [DO NOT TRANSLATE] -->
+    <string name="help_url_location_access" translatable="false"></string>
 
     <!-- User account title [CHAR LIMIT=30] -->
     <string name="user_account_title">Account for content</string>
diff --git a/res/xml/device_info_settings.xml b/res/xml/device_info_settings.xml
index 324deaa..4fabc9d 100644
--- a/res/xml/device_info_settings.xml
+++ b/res/xml/device_info_settings.xml
@@ -89,6 +89,10 @@
         </PreferenceScreen>
         -->
 
+        <Preference android:key="regulatory_info"
+                android:title="@string/regulatory_information"
+                android:fragment="com.android.settings.RegulatoryInfoFragment"/>
+
         <!-- Device hardware model -->
         <Preference android:key="device_model" 
                 style="?android:preferenceInformationStyle"
@@ -106,7 +110,7 @@
                 style="?android:preferenceInformationStyle"
                 android:title="@string/fcc_equipment_id"
                 android:summary="@string/device_info_default"/>
-                
+
         <!-- Device Baseband version -->
         <Preference android:key="baseband_version" 
                 style="?android:preferenceInformationStyle"
diff --git a/src/com/android/settings/AppWidgetPickActivity.java b/src/com/android/settings/AppWidgetPickActivity.java
index f573edf..f242dcf 100644
--- a/src/com/android/settings/AppWidgetPickActivity.java
+++ b/src/com/android/settings/AppWidgetPickActivity.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.os.SystemProperties;
 import android.util.Log;
 
 import java.text.Collator;
@@ -54,7 +55,11 @@
      * activity is binding.
      */
     private int mAppWidgetId;
-    
+
+    // Enable testing launcher widgets in keyguard.  For testing purposes only.
+    private final boolean mIgnoreFilter = false || SystemProperties.getBoolean(
+            "ro.keyguard_ignore_filter", false);
+
     @Override
     public void onCreate(Bundle icicle) {
         mPackageManager = getPackageManager();
@@ -257,7 +262,7 @@
      */
     void putInstalledAppWidgets(List<PickAdapter.Item> items, int categoryFilter, int featuresFilter) {
         List<AppWidgetProviderInfo> installed = mAppWidgetManager.getInstalledProviders();
-        putAppWidgetItems(installed, null, items, categoryFilter, featuresFilter, false);
+        putAppWidgetItems(installed, null, items, categoryFilter, featuresFilter, mIgnoreFilter );
     }
 
     /**
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index 7c1832f6..8d51e10 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -461,7 +461,7 @@
 
         mMenuAutoSync = menu.findItem(R.id.data_usage_menu_auto_sync);
         mMenuAutoSync.setChecked(ContentResolver.getMasterSyncAutomatically());
-        mMenuAutoSync.setVisible(isOwner && !appDetailMode);
+        mMenuAutoSync.setVisible(!appDetailMode);
 
         final MenuItem split4g = menu.findItem(R.id.data_usage_menu_split_4g);
         split4g.setVisible(hasReadyMobile4gRadio(context) && isOwner && !appDetailMode);
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 8254233..258ea64 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -49,6 +49,7 @@
     private static final String KEY_CONTAINER = "container";
     private static final String KEY_TEAM = "team";
     private static final String KEY_CONTRIBUTORS = "contributors";
+    private static final String KEY_REGULATORY_INFO = "regulatory_info";
     private static final String KEY_TERMS = "terms";
     private static final String KEY_LICENSE = "license";
     private static final String KEY_COPYRIGHT = "copyright";
@@ -132,11 +133,12 @@
                 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
 
         // Read platform settings for additional system update setting
-        boolean isUpdateSettingAvailable =
-                getResources().getBoolean(R.bool.config_additional_system_update_setting_enable);
-        if (isUpdateSettingAvailable == false) {
-            getPreferenceScreen().removePreference(findPreference(KEY_UPDATE_SETTING));
-        }
+        removePreferenceIfBoolFalse(KEY_UPDATE_SETTING,
+                R.bool.config_additional_system_update_setting_enable);
+
+        // Remove regulatory information if not enabled.
+        removePreferenceIfBoolFalse(KEY_REGULATORY_INFO,
+                R.bool.config_show_regulatory_info);
     }
 
     @Override
@@ -160,8 +162,7 @@
 
     private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
             String preference, String property ) {
-        if (SystemProperties.get(property).equals(""))
-        {
+        if (SystemProperties.get(property).equals("")) {
             // Property is missing so remove preference from group
             try {
                 preferenceGroup.removePreference(findPreference(preference));
@@ -172,6 +173,12 @@
         }
     }
 
+    private void removePreferenceIfBoolFalse(String preference, int resId) {
+        if (!getResources().getBoolean(resId)) {
+            getPreferenceScreen().removePreference(findPreference(preference));
+        }
+    }
+
     private void setStringSummary(String preference, String value) {
         try {
             findPreference(preference).setSummary(value);
diff --git a/src/com/android/settings/LocationSettings.java b/src/com/android/settings/LocationSettings.java
index 4153485..cfbbe26 100644
--- a/src/com/android/settings/LocationSettings.java
+++ b/src/com/android/settings/LocationSettings.java
@@ -185,6 +185,10 @@
         return true;
     }
 
+    @Override
+    public int getHelpResource() {
+        return R.string.help_url_location_access;
+    }
 }
 
 class WrappingSwitchPreference extends SwitchPreference {
diff --git a/src/com/android/settings/RegulatoryInfoFragment.java b/src/com/android/settings/RegulatoryInfoFragment.java
new file mode 100644
index 0000000..7ee13bf
--- /dev/null
+++ b/src/com/android/settings/RegulatoryInfoFragment.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.DialogFragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.settings.R;
+
+/**
+ * {@link DialogFragment} that displays regulatory information.
+ * "About phone" will show a preference that displays this fragment when
+ * clicked if R.bool.config_show_regulatory_info is true.
+ */
+public class RegulatoryInfoFragment extends DialogFragment {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.regulatory_info, container, false);
+    }
+}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index d896a68..64e2ec3 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -21,7 +21,6 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
@@ -258,12 +257,7 @@
         mUserSelectedWidget = root.findPreference(KEY_CHOOSE_USER_SELECTED_LOCKSCREEN_WIDGET);
         if (mUserSelectedWidget != null) {
             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getActivity());
-            int appWidgetId = -1;
-            String appWidgetIdString = Settings.Secure.getString(
-                    getContentResolver(), Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID);
-            if (appWidgetIdString != null) {;
-                appWidgetId = (int) Integer.decode(appWidgetIdString);
-            }
+            int appWidgetId = getUserSelectedAppWidgetId();
             if (appWidgetId == -1) {
                 mUserSelectedWidget.setSummary(getResources().getString(R.string.widget_none));
             } else {
@@ -277,6 +271,16 @@
         return root;
     }
 
+    private int getUserSelectedAppWidgetId() {
+        int appWidgetId = -1;
+        String appWidgetIdString = Settings.Secure.getString(
+                getContentResolver(), Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID);
+        if (appWidgetIdString != null) {;
+            appWidgetId = (int) Integer.decode(appWidgetIdString);
+        }
+        return appWidgetId;
+    }
+
     private boolean isNonMarketAppsAllowed() {
         return Settings.Global.getInt(getContentResolver(),
                                       Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0;
@@ -455,8 +459,7 @@
             Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
             // Found in KeyguardHostView.java
             final int KEYGUARD_HOST_ID = 0x4B455947;
-            int appWidgetId = AppWidgetHost.allocateAppWidgetIdForHost(
-                    "com.android.internal.policy.impl.keyguard", KEYGUARD_HOST_ID);
+            int appWidgetId = AppWidgetHost.allocateAppWidgetIdForSystem(KEYGUARD_HOST_ID);
             if (appWidgetId != -1) {
                 pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                 pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
@@ -587,17 +590,24 @@
                 } else {
                     // Otherwise just add it
                     if (noWidget) {
+                        // If we selected "none", delete the allocated id
+                        AppWidgetHost.deleteAppWidgetIdForSystem(appWidgetId);
                         data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
                     }
                     onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
                 }
-            } else if (requestCode == REQUEST_CREATE_APPWIDGET && resultCode == Activity.RESULT_OK) {
+            } else if (
+                    requestCode == REQUEST_CREATE_APPWIDGET && resultCode == Activity.RESULT_OK) {
+                // If a widget existed before, delete it
+                int oldAppWidgetId = getUserSelectedAppWidgetId();
+                if (oldAppWidgetId != -1) {
+                    AppWidgetHost.deleteAppWidgetIdForSystem(oldAppWidgetId);
+                }
                 Settings.Secure.putString(getContentResolver(),
                         Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID,
                         Integer.toString(appWidgetId));
-
             } else {
-                AppWidgetHost.deleteAppWidgetIdForHost(appWidgetId);
+                AppWidgetHost.deleteAppWidgetIdForSystem(appWidgetId);
             }
         }
         createPreferenceHierarchy();
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 1564803..df44e91 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -79,7 +79,7 @@
     private String[] mWifiRegexs;
 
     private String[] mBluetoothRegexs;
-    private AtomicReference<BluetoothPan> mBluetoothPan;
+    private AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<BluetoothPan>();
 
     private static final String WIFI_AP_SSID_AND_SECURITY = "wifi_ap_ssid_and_security";
     private static final int CONFIG_SUBTEXT = R.string.wifi_tether_configure_subtext;
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 777a712..1a5c82c 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -23,25 +23,41 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
+import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Bundle;
-import android.os.SystemProperties;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.preference.Preference;
 import android.preference.PreferenceActivity.Header;
 import android.preference.PreferenceFrameLayout;
 import android.preference.PreferenceGroup;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Profile;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ListView;
 import android.widget.TabWidget;
 
+import com.android.settings.users.ProfileUpdateReceiver;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.net.InetAddress;
 import java.util.Iterator;
 import java.util.List;
@@ -445,4 +461,43 @@
             return R.string.tether_settings_title_bluetooth;
         }
     }
+
+    /* Used by UserSettings as well. Call this on a non-ui thread. */
+    public static boolean copyMeProfilePhoto(Context context, UserInfo user) {
+        Uri contactUri = Profile.CONTENT_URI;
+
+        InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
+                    context.getContentResolver(),
+                    contactUri, true);
+        // If there's no profile photo, assign a default avatar
+        if (avatarDataStream == null) {
+            return false;
+        }
+        int userId = user != null ? user.id : UserHandle.myUserId();
+        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        Bitmap icon = BitmapFactory.decodeStream(avatarDataStream);
+        um.setUserIcon(userId, icon);
+        try {
+            avatarDataStream.close();
+        } catch (IOException ioe) { }
+        return true;
+    }
+
+    public static String getMeProfileName(Context context) {
+        Cursor cursor = context.getContentResolver().query(
+                    Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
+                    null, null, null);
+        if (cursor == null) {
+            return null;
+        }
+
+        try {
+            if (cursor.moveToFirst()) {
+                return cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+            }
+        } finally {
+            cursor.close();
+        }
+        return null;
+    }
 }
diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java
index cca9086..2ce6779 100644
--- a/src/com/android/settings/applications/ApplicationsState.java
+++ b/src/com/android/settings/applications/ApplicationsState.java
@@ -163,8 +163,12 @@
         private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
-            if (object1.info.enabled != object2.info.enabled) {
-                return object1.info.enabled ? -1 : 1;
+            final boolean normal1 = object1.info.enabled
+                    && (object1.info.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
+            final boolean normal2 = object2.info.enabled
+                    && (object2.info.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
+            if (normal1 != normal2) {
+                return normal1 ? -1 : 1;
             }
             return sCollator.compare(object1.label, object2.label);
         }
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index e056f6a..2284b91 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -55,6 +55,8 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.preference.PreferenceActivity;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -66,6 +68,9 @@
 import java.util.ArrayList;
 import java.util.List;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
@@ -92,12 +97,12 @@
         implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
         ApplicationsState.Callbacks {
     private static final String TAG="InstalledAppDetails";
-    static final boolean SUPPORT_DISABLE_APPS = true;
     private static final boolean localLOGV = false;
     
     public static final String ARG_PACKAGE_NAME = "package";
 
     private PackageManager mPm;
+    private UserManager mUserManager;
     private IUsbManager mUsbManager;
     private AppWidgetManager mAppWidgetManager;
     private DevicePolicyManager mDpm;
@@ -167,7 +172,14 @@
     private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
     private static final int DLG_DISABLE = DLG_BASE + 7;
     private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
-    
+
+    // Menu identifiers
+    public static final int UNINSTALL_ALL_USERS_MENU = 1;
+
+    // Result code identifiers
+    public static final int REQUEST_UNINSTALL = 1;
+    public static final int REQUEST_MANAGE_SPACE = 2;
+
     private Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             // If the fragment is gone, don't process any more messages.
@@ -303,30 +315,28 @@
         } else {
             if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                 enabled = false;
-                if (SUPPORT_DISABLE_APPS) {
-                    try {
-                        // Try to prevent the user from bricking their phone
-                        // by not allowing disabling of apps signed with the
-                        // system cert and any launcher app in the system.
-                        PackageInfo sys = mPm.getPackageInfo("android",
-                                PackageManager.GET_SIGNATURES);
-                        Intent intent = new Intent(Intent.ACTION_MAIN);
-                        intent.addCategory(Intent.CATEGORY_HOME);
-                        intent.setPackage(mAppEntry.info.packageName);
-                        List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
-                        if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
-                            // Disable button for core system applications.
-                            mUninstallButton.setText(R.string.disable_text);
-                        } else if (mAppEntry.info.enabled) {
-                            mUninstallButton.setText(R.string.disable_text);
-                            enabled = true;
-                        } else {
-                            mUninstallButton.setText(R.string.enable_text);
-                            enabled = true;
-                        }
-                    } catch (PackageManager.NameNotFoundException e) {
-                        Log.w(TAG, "Unable to get package info", e);
+                try {
+                    // Try to prevent the user from bricking their phone
+                    // by not allowing disabling of apps signed with the
+                    // system cert and any launcher app in the system.
+                    PackageInfo sys = mPm.getPackageInfo("android",
+                            PackageManager.GET_SIGNATURES);
+                    Intent intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(Intent.CATEGORY_HOME);
+                    intent.setPackage(mAppEntry.info.packageName);
+                    List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
+                    if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
+                        // Disable button for core system applications.
+                        mUninstallButton.setText(R.string.disable_text);
+                    } else if (mAppEntry.info.enabled) {
+                        mUninstallButton.setText(R.string.disable_text);
+                        enabled = true;
+                    } else {
+                        mUninstallButton.setText(R.string.enable_text);
+                        enabled = true;
                     }
+                } catch (PackageManager.NameNotFoundException e) {
+                    Log.w(TAG, "Unable to get package info", e);
                 }
             } else if ((mPackageInfo.applicationInfo.flags
                     & ApplicationInfo.FLAG_INSTALLED) == 0) {
@@ -369,10 +379,11 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        
+
         mState = ApplicationsState.getInstance(getActivity().getApplication());
         mSession = mState.newSession(this);
         mPm = getActivity().getPackageManager();
+        mUserManager = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
         IBinder b = ServiceManager.getService(Context.USB_SERVICE);
         mUsbManager = IUsbManager.Stub.asInterface(b);
         mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
@@ -380,6 +391,10 @@
         mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
 
         mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
+
+        retrieveAppEntry();
+
+        setHasOptionsMenu(true);
     }
 
     @Override
@@ -428,6 +443,51 @@
         return view;
     }
 
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        boolean showIt = true;
+        if (mUpdatedSysApp) {
+            showIt = false;
+        } else if (mAppEntry == null) {
+            showIt = false;
+        } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+            showIt = false;
+        } else if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
+            showIt = false;
+        } else if (UserHandle.myUserId() != 0) {
+            showIt = false;
+        } else if (mUserManager.getUsers().size() < 1) {
+            showIt = false;
+        }
+        menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        int menuId = item.getItemId();
+        if (menuId == UNINSTALL_ALL_USERS_MENU) {
+            uninstallPkg(mAppEntry.info.packageName, true);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == REQUEST_UNINSTALL) {
+            if (!refreshUi()) {
+                setIntentAndFinish(true, true);
+            }
+        }
+    }
+
     // Utility method to set applicaiton label and icon.
     private void setAppLabelAndIcon(PackageInfo pkgInfo) {
         View appSnippet = mRootView.findViewById(R.id.app_snippet);
@@ -493,10 +553,7 @@
     public void onRunningStateChanged(boolean running) {
     }
 
-    private boolean refreshUi() {
-        if (mMoveInProgress) {
-            return true;
-        }
+    private String retrieveAppEntry() {
         final Bundle args = getArguments();
         String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
         if (packageName == null) {
@@ -507,7 +564,15 @@
             }
         }
         mAppEntry = mState.getEntry(packageName);
-        
+        return packageName;
+    }
+
+    private boolean refreshUi() {
+        if (mMoveInProgress) {
+            return true;
+        }
+        final String packageName = retrieveAppEntry();
+
         if (mAppEntry == null) {
             return false; // onCreate must have failed, make sure to exit
         }
@@ -925,7 +990,7 @@
                             new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
                             // Clear user data here
-                            getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName);
+                            getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName, false);
                         }
                     })
                     .setNegativeButton(R.string.dlg_cancel, null)
@@ -1021,12 +1086,12 @@
         }
     }
 
-    private void uninstallPkg(String packageName) {
+    private void uninstallPkg(String packageName, boolean allUsers) {
          // Create new intent to launch Uninstaller activity
         Uri packageURI = Uri.parse("package:"+packageName);
-        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
-        startActivity(uninstallIntent);
-        setIntentAndFinish(true, true);
+        Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+        uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
+        startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
     }
 
     private void forceStopPackage(String pkgName) {
@@ -1139,7 +1204,7 @@
                     } catch (NameNotFoundException e) {
                     }
                 } else {
-                    uninstallPkg(packageName);
+                    uninstallPkg(packageName, false);
                 }
             }
         } else if(v == mActivitiesButton) {
@@ -1160,7 +1225,7 @@
                     Intent intent = new Intent(Intent.ACTION_DEFAULT);
                     intent.setClassName(mAppEntry.info.packageName,
                             mAppEntry.info.manageSpaceActivityName);
-                    startActivityForResult(intent, -1);
+                    startActivityForResult(intent, REQUEST_MANAGE_SPACE);
                 }
             } else {
                 showDialogInner(DLG_CLEAR_DATA, 0);
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 0a73b02..b94d944 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -774,8 +774,12 @@
                     holder.appIcon.setImageDrawable(entry.icon);
                 }
                 holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
-                if (InstalledAppDetails.SUPPORT_DISABLE_APPS) {
-                    holder.disabled.setVisibility(entry.info.enabled ? View.GONE : View.VISIBLE);
+                if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+                    holder.disabled.setVisibility(View.VISIBLE);
+                    holder.disabled.setText(R.string.not_installed);
+                } else if (!entry.info.enabled) {
+                    holder.disabled.setVisibility(View.VISIBLE);
+                    holder.disabled.setText(R.string.disabled);
                 } else {
                     holder.disabled.setVisibility(View.GONE);
                 }
@@ -997,7 +1001,6 @@
     
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        Log.i(TAG, "onCreateOptionsMenu in " + this + ": " + menu);
         mOptionsMenu = menu;
         // note: icons removed for now because the cause the new action
         // bar UI to be very confusing.
diff --git a/src/com/android/settings/applications/RunningServiceDetails.java b/src/com/android/settings/applications/RunningServiceDetails.java
index 52ed458..555f192 100644
--- a/src/com/android/settings/applications/RunningServiceDetails.java
+++ b/src/com/android/settings/applications/RunningServiceDetails.java
@@ -436,22 +436,24 @@
 
         mNumServices = mNumProcesses = 0;
 
-        if (mMergedItem.mUser != null) {
-            ArrayList<RunningState.MergedItem> items;
-            if (mShowBackground) {
-                items = new ArrayList<RunningState.MergedItem>(mMergedItem.mChildren);
-                Collections.sort(items, mState.mBackgroundComparator);
+        if (mMergedItem != null) {
+            if (mMergedItem.mUser != null) {
+                ArrayList<RunningState.MergedItem> items;
+                if (mShowBackground) {
+                    items = new ArrayList<RunningState.MergedItem>(mMergedItem.mChildren);
+                    Collections.sort(items, mState.mBackgroundComparator);
+                } else {
+                    items = mMergedItem.mChildren;
+                }
+                for (int i=0; i<items.size(); i++) {
+                    addDetailsViews(items.get(i), true, false);
+                }
+                for (int i=0; i<items.size(); i++) {
+                    addDetailsViews(items.get(i), false, true);
+                }
             } else {
-                items = mMergedItem.mChildren;
+                addDetailsViews(mMergedItem, true, true);
             }
-            for (int i=0; i<items.size(); i++) {
-                addDetailsViews(items.get(i), true, false);
-            }
-            for (int i=0; i<items.size(); i++) {
-                addDetailsViews(items.get(i), false, true);
-            }
-        } else {
-            addDetailsViews(mMergedItem, true, true);
         }
     }
     
diff --git a/src/com/android/settings/bluetooth/PBAPServerProfile.java b/src/com/android/settings/bluetooth/PbapServerProfile.java
similarity index 99%
rename from src/com/android/settings/bluetooth/PBAPServerProfile.java
rename to src/com/android/settings/bluetooth/PbapServerProfile.java
index 7217574..1f5ca32 100755
--- a/src/com/android/settings/bluetooth/PBAPServerProfile.java
+++ b/src/com/android/settings/bluetooth/PbapServerProfile.java
@@ -30,7 +30,7 @@
 import java.util.List;
 
 /**
- *PBAPServer Profile
+ * PBAPServer Profile
  */
 final class PbapServerProfile implements LocalBluetoothProfile {
     private static final String TAG = "PbapServerProfile";
diff --git a/src/com/android/settings/deviceinfo/FileItemInfoLayout.java b/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
index 990f7f2..542d7c9 100644
--- a/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
+++ b/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
@@ -2,10 +2,9 @@
 
 package com.android.settings.deviceinfo;
 
-import com.android.settings.R;
-
 import android.content.Context;
-import android.os.Environment;
+import android.os.Environment.UserEnvironment;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.view.ViewDebug;
 import android.widget.CheckBox;
@@ -13,6 +12,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.android.settings.R;
+
 /**
  * Handles display of a single row entry on Settings --> Storage --> Misc Files screen
  */
@@ -20,8 +21,9 @@
     private TextView mFileNameView;
     private TextView mFileSizeView;
     private CheckBox mCheckbox;
-    private static final int mLengthExternalStorageDirPrefix =
-            Environment.getExternalStorageDirectory().getAbsolutePath().length() + 1;
+
+    private static final int sLengthExternalStorageDirPrefix = new UserEnvironment(
+            UserHandle.myUserId()).getExternalStorageDirectory().getAbsolutePath().length() + 1;
 
     public FileItemInfoLayout(Context context) {
         this(context, null);
@@ -51,7 +53,7 @@
     }
 
     public void setFileName(String fileName) {
-        mFileNameView.setText(fileName.substring(mLengthExternalStorageDirPrefix));
+        mFileNameView.setText(fileName.substring(sLengthExternalStorageDirPrefix));
     }
 
     public void setFileSize(String filesize) {
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 173efef..9bd5538 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -54,6 +54,7 @@
 import com.android.internal.os.PowerProfile;
 import com.android.settings.R;
 import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
+import com.android.settings.users.UserUtils;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -768,11 +769,7 @@
             UserInfo info = mUm.getUserInfo(userId);
             Drawable icon = null;
             if (info != null && info.iconPath != null) {
-                try {
-                    icon = Drawable.createFromPath(info.iconPath);
-                } catch (Exception e) {
-                    Log.w(TAG, "Failure loading user picture " + info.iconPath, e);
-                }
+                icon = UserUtils.getUserIcon(mUm, info);
             }
             String name = info != null ? info.name : null;
             if (name == null) {
diff --git a/src/com/android/settings/users/ProfileUpdateReceiver.java b/src/com/android/settings/users/ProfileUpdateReceiver.java
index 5513608..88daa58 100644
--- a/src/com/android/settings/users/ProfileUpdateReceiver.java
+++ b/src/com/android/settings/users/ProfileUpdateReceiver.java
@@ -19,64 +19,45 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.UserInfo;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
+import android.content.SharedPreferences;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Profile;
-import android.util.Log;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
 
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import com.android.settings.Utils;
+
 
 /**
  * Watches for changes to Me Profile in Contacts and writes the photo to the User Manager.
  */
 public class ProfileUpdateReceiver extends BroadcastReceiver {
 
+    private static final String KEY_PROFILE_NAME_COPIED_ONCE = "name_copied_once";
+
     @Override
     public void onReceive(final Context context, Intent intent) {
         // Profile changed, lets get the photo and write to user manager
         new Thread() {
             public void run() {
-                copyProfilePhoto(context, null);
+                Utils.copyMeProfilePhoto(context, null);
+                copyProfileName(context);
             }
         }.start();
     }
 
-    /* Used by UserSettings as well. Call this on a non-ui thread. */
-    static boolean copyProfilePhoto(Context context, UserInfo user) {
-        Uri contactUri = Profile.CONTENT_URI;
+    static void copyProfileName(Context context) {
+        SharedPreferences prefs = context.getSharedPreferences("profile", Context.MODE_PRIVATE);
+        if (prefs.contains(KEY_PROFILE_NAME_COPIED_ONCE)) {
+            return;
+        }
 
-        InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
-                    context.getContentResolver(),
-                    contactUri, true);
-        // If there's no profile photo, assign a default avatar
-        if (avatarDataStream == null) {
-            return false;
-        }
-        int userId = user != null ? user.id : UserHandle.myUserId();
+        int userId = UserHandle.myUserId();
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        ParcelFileDescriptor fd = um.setUserIcon(userId);
-        FileOutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-        byte[] buffer = new byte[4096];
-        int readSize;
-        try {
-            while ((readSize = avatarDataStream.read(buffer)) > 0) {
-                os.write(buffer, 0, readSize);
-            }
-            return true;
-        } catch (IOException ioe) {
-            Log.e("copyProfilePhoto", "Error copying profile photo " + ioe);
-        } finally {
-            try {
-                os.close();
-                avatarDataStream.close();
-            } catch (IOException ioe) { }
+        String profileName = Utils.getMeProfileName(context);
+        if (profileName != null && profileName.length() > 0) {
+            um.setUserName(userId, profileName);
+            // Flag that we've written the profile one time at least. No need to do it in the future.
+            prefs.edit().putBoolean(KEY_PROFILE_NAME_COPIED_ONCE, true).commit();
         }
-        return false;
     }
 }
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 28fe4c1..079996e 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.users;
 
+import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
@@ -29,6 +30,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Bitmap.CompressFormat;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -36,6 +38,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.preference.EditTextPreference;
@@ -46,7 +49,9 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Profile;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.text.InputType;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -54,12 +59,15 @@
 import android.view.View.OnClickListener;
 import android.widget.Toast;
 
+import com.android.internal.telephony.MccTable;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 
 public class UserSettings extends SettingsPreferenceFragment
@@ -77,8 +85,10 @@
 
     private static final int DIALOG_CONFIRM_REMOVE = 1;
     private static final int DIALOG_ADD_USER = 2;
+    private static final int DIALOG_SETUP_USER = 3;
 
     private static final int MESSAGE_UPDATE_LIST = 1;
+    private static final int MESSAGE_SETUP_USER = 2;
 
     private static final int[] USER_DRAWABLES = {
         R.drawable.ic_user,
@@ -98,11 +108,13 @@
     private Preference mMePreference;
     private EditTextPreference mNicknamePreference;
     private int mRemovingUserId = -1;
+    private int mAddedUserId = 0;
     private boolean mAddingUser;
     private boolean mProfileExists;
 
     private final Object mUserLock = new Object();
     private UserManager mUserManager;
+    private SparseArray<Drawable> mUserIcons = new SparseArray<Drawable>();
 
     private Handler mHandler = new Handler() {
         @Override
@@ -111,14 +123,24 @@
             case MESSAGE_UPDATE_LIST:
                 updateUserList();
                 break;
+            case MESSAGE_SETUP_USER:
+                onUserCreated(msg.arg1);
+                break;
             }
         }
     };
 
     private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
-
         @Override
         public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
+                mRemovingUserId = -1;
+            } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) {
+                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                if (userHandle != -1) {
+                    mUserIcons.remove(userHandle);
+                }
+            }
             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
         }
     };
@@ -136,11 +158,14 @@
         }
         mNicknamePreference = (EditTextPreference) findPreference(KEY_USER_NICKNAME);
         mNicknamePreference.setOnPreferenceChangeListener(this);
-        mNicknamePreference.setSummary(mUserManager.getUserInfo(UserHandle.myUserId()).name);
+        mNicknamePreference.getEditText().setInputType(
+                InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
         loadProfile();
         setHasOptionsMenu(true);
-        getActivity().registerReceiver(mUserChangeReceiver,
-                new IntentFilter(Intent.ACTION_USER_REMOVED));
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+        getActivity().registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
+                mHandler);
     }
 
     @Override
@@ -169,6 +194,7 @@
             removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
                     | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
         }
+        super.onCreateOptionsMenu(menu, inflater);
     }
 
     @Override
@@ -207,7 +233,13 @@
 
     private void finishLoadProfile(String profileName) {
         mMePreference.setTitle(profileName);
-        setPhotoId(mMePreference, mUserManager.getUserInfo(UserHandle.myUserId()));
+        int myUserId = UserHandle.myUserId();
+        Bitmap b = mUserManager.getUserIcon(myUserId);
+        if (b != null) {
+            Drawable d = new BitmapDrawable(b);
+            mMePreference.setIcon(d);
+            mUserIcons.put(myUserId, d);
+        }
     }
 
     private void onAddUserClicked() {
@@ -229,13 +261,22 @@
         }
     }
 
+    private void onUserCreated(int userId) {
+        mAddedUserId = userId;
+        showDialog(DIALOG_SETUP_USER);
+    }
+
     @Override
     public Dialog onCreateDialog(int dialogId) {
         switch (dialogId) {
             case DIALOG_CONFIRM_REMOVE:
                 return new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.user_confirm_remove_title)
-                    .setMessage(R.string.user_confirm_remove_message)
+                    .setTitle(UserHandle.myUserId() == mRemovingUserId
+                            ? R.string.user_confirm_remove_self_title
+                            : R.string.user_confirm_remove_title)
+                    .setMessage(UserHandle.myUserId() == mRemovingUserId
+                            ? R.string.user_confirm_remove_self_message
+                            : R.string.user_confirm_remove_message)
                     .setPositiveButton(android.R.string.ok,
                         new DialogInterface.OnClickListener() {
                             public void onClick(DialogInterface dialog, int which) {
@@ -256,6 +297,19 @@
                 })
                 .setNegativeButton(android.R.string.cancel, null)
                 .create();
+            case DIALOG_SETUP_USER:
+                return new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.user_setup_dialog_title)
+                .setMessage(R.string.user_setup_dialog_message)
+                .setPositiveButton(R.string.user_setup_button_setup_now,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            switchUserNow(mAddedUserId);
+                        }
+                })
+                .setNegativeButton(R.string.user_setup_button_setup_later, null)
+                .create();
+
             default:
                 return null;
         }
@@ -268,10 +322,8 @@
             new Thread() {
                 public void run() {
                     synchronized (mUserLock) {
-                        // TODO: Show some progress while removing the user
                         mUserManager.removeUser(mRemovingUserId);
                         mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
-                        mRemovingUserId = -1;
                     }
                 }
             }.start();
@@ -279,11 +331,12 @@
     }
 
     private void removeThisUser() {
-        // TODO:
-        Toast.makeText(getActivity(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
-
-        synchronized (mUserLock) {
-            mRemovingUserId = -1;
+        try {
+            ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
+            ((UserManager) getActivity().getSystemService(Context.USER_SERVICE))
+                    .removeUser(UserHandle.myUserId());
+        } catch (RemoteException re) {
+            Log.e(TAG, "Unable to remove self user");
         }
     }
 
@@ -302,22 +355,38 @@
                     synchronized (mUserLock) {
                         mAddingUser = false;
                         mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
+                        mHandler.sendMessage(mHandler.obtainMessage(
+                                MESSAGE_SETUP_USER, user.id, user.serialNumber));
                     }
                 }
             }.start();
         }
     }
 
+    private void switchUserNow(int userId) {
+        try {
+            ActivityManagerNative.getDefault().switchUser(userId);
+        } catch (RemoteException re) {
+            // Nothing to do
+        }
+    }
+
     private void updateUserList() {
+        if (getActivity() == null) return;
         List<UserInfo> users = mUserManager.getUsers();
 
         mUserListCategory.removeAll();
         mUserListCategory.setOrderingAsAdded(false);
 
+        final ArrayList<Integer> missingIcons = new ArrayList<Integer>();
         for (UserInfo user : users) {
             Preference pref;
-            if (user.id == UserHandle.myUserId()) {
+            if (user.id == mRemovingUserId) {
+                continue;
+            } else if (user.id == UserHandle.myUserId()) {
                 pref = mMePreference;
+                mNicknamePreference.setText(user.name);
+                mNicknamePreference.setSummary(user.name);
             } else {
                 pref = new UserPreference(getActivity(), null, user.id,
                         UserHandle.myUserId() == UserHandle.USER_OWNER, this);
@@ -330,7 +399,12 @@
                 pref.setTitle(user.name);
             }
             if (user.iconPath != null) {
-                setPhotoId(pref, user);
+                if (mUserIcons.get(user.id) == null) {
+                    missingIcons.add(user.id);
+                    pref.setIcon(R.drawable.ic_user);
+                } else {
+                    setPhotoId(pref, user);
+                }
             }
         }
         // Add a temporary entry for the user being created
@@ -344,50 +418,58 @@
             mUserListCategory.addPreference(pref);
         }
         getActivity().invalidateOptionsMenu();
+
+        // Load the icons
+        if (missingIcons.size() > 0) {
+            loadIconsAsync(missingIcons);
+        }
     }
 
+    private void loadIconsAsync(List<Integer> missingIcons) {
+        new AsyncTask<List<Integer>, Void, Void>() {
+            @Override
+            protected void onPostExecute(Void result) {
+                updateUserList();
+            }
+
+            @Override
+            protected Void doInBackground(List<Integer>... values) {
+                if (getActivity() == null) return null;
+                for (int userId : values[0]) {
+                    Bitmap bitmap = mUserManager.getUserIcon(userId);
+                    Drawable d = new BitmapDrawable(getResources(), bitmap);
+                    mUserIcons.append(userId, d);
+                }
+                return null;
+            }
+        }.execute(missingIcons);
+
+    }
     private void assignProfilePhoto(final UserInfo user) {
-        if (!ProfileUpdateReceiver.copyProfilePhoto(getActivity(), user)) {
+        if (!Utils.copyMeProfilePhoto(getActivity(), user)) {
             assignDefaultPhoto(user);
         }
     }
 
     private String getProfileName() {
-        Cursor cursor = getActivity().getContentResolver().query(
-                    Profile.CONTENT_URI, CONTACT_PROJECTION, null, null, null);
-        if (cursor == null) {
-            Log.w(TAG, "getProfileName() returned NULL cursor!"
-                    + " contact uri used " + Profile.CONTENT_URI);
-            return null;
+        String name = Utils.getMeProfileName(getActivity());
+        if (name != null) {
+            mProfileExists = true;
         }
-
-        try {
-            if (cursor.moveToFirst()) {
-                mProfileExists = true;
-                return cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
-            }
-        } finally {
-            cursor.close();
-        }
-        return null;
+        return name;
     }
 
     private void assignDefaultPhoto(UserInfo user) {
         Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                 USER_DRAWABLES[user.id % USER_DRAWABLES.length]);
-        ParcelFileDescriptor fd = mUserManager.setUserIcon(user.id);
-        if (fd != null) {
-            bitmap.compress(CompressFormat.PNG, 100,
-                    new ParcelFileDescriptor.AutoCloseOutputStream(fd));
-        }
+        mUserManager.setUserIcon(user.id, bitmap);
     }
 
     private void setPhotoId(Preference pref, UserInfo user) {
-        ParcelFileDescriptor fd = mUserManager.setUserIcon(user.id);
-        Drawable d = Drawable.createFromStream(new ParcelFileDescriptor.AutoCloseInputStream(fd),
-                user.iconPath);
-        if (d == null) return;
-        pref.setIcon(d);
+        Drawable d = mUserIcons.get(user.id); // UserUtils.getUserIcon(mUserManager, user);
+        if (d != null) {
+            pref.setIcon(d);
+        }
     }
 
     private void setUserName(String name) {
@@ -443,4 +525,8 @@
         return false;
     }
 
+    @Override
+    public int getHelpResource() {
+        return R.string.help_url_users;
+    }
 }
diff --git a/src/com/android/settings/users/UserUtils.java b/src/com/android/settings/users/UserUtils.java
new file mode 100644
index 0000000..433cbd3
--- /dev/null
+++ b/src/com/android/settings/users/UserUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 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.users;
+
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.ParcelFileDescriptor;
+import android.os.UserManager;
+
+public class UserUtils {
+
+    public static Drawable getUserIcon(UserManager um, UserInfo user) {
+        if (user.iconPath == null) return null;
+        Bitmap icon = um.getUserIcon(user.id);
+        if (icon == null) return null;
+        return new BitmapDrawable(icon);
+    }
+}