User management UI: take 2

Single screen user management, also visible on secondary users.
Work in progress, especially with respect to synchronizing with
the Me profile.

Change-Id: Id6e94a85d53356847e4e019c52e3388de9ecb354
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index d5a90f6..6f2002a 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -107,14 +107,13 @@
             R.id.application_settings,
             R.id.personal_section,
             R.id.security_settings,
+            R.id.user_settings,
             R.id.account_settings,
             R.id.account_add,
             R.id.system_section,
             R.id.about_settings
     };
 
-    private boolean mEnableUserManagement = false;
-
     // TODO: Update Call Settings based on airplane mode state.
 
     protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
@@ -129,11 +128,6 @@
             getWindow().setUiOptions(0);
         }
 
-        if (android.provider.Settings.Secure.getInt(getContentResolver(), "multiuser_enabled", -1)
-                > 0) {
-            mEnableUserManagement = true;
-        }
-
         mAuthenticatorHelper = new AuthenticatorHelper();
         mAuthenticatorHelper.updateAuthDescriptions(this);
         mAuthenticatorHelper.onAccountsUpdated(this, null);
@@ -418,8 +412,7 @@
                 int headerIndex = i + 1;
                 i = insertAccountsHeaders(target, headerIndex);
             } else if (id == R.id.user_settings) {
-                if (!mEnableUserManagement
-                        || !UserHandle.MU_ENABLED || UserHandle.myUserId() != 0
+                if (!UserHandle.MU_ENABLED
                         || !getResources().getBoolean(R.bool.enable_user_management)
                         || Utils.isMonkeyRunning()) {
                     target.remove(header);
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
deleted file mode 100644
index 518c6b6..0000000
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
-import android.preference.Preference;
-import android.preference.PreferenceGroup;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-import com.android.settings.DialogCreatable;
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-
-import java.util.HashMap;
-import java.util.List;
-
-public class UserDetailsSettings extends SettingsPreferenceFragment
-        implements Preference.OnPreferenceChangeListener, DialogCreatable,
-                   Preference.OnPreferenceClickListener {
-
-    private static final String TAG = "UserDetailsSettings";
-
-    private static final int MENU_REMOVE_USER = Menu.FIRST;
-    private static final int DIALOG_CONFIRM_REMOVE = 1;
-
-    private static final String KEY_USER_NAME = "user_name";
-    private static final String KEY_USER_PICTURE = "user_picture";
-
-    public static final String EXTRA_USER_ID = "user_id";
-
-    private static final int RESULT_PICK_IMAGE = 1;
-    private static final int RESULT_CROP_IMAGE = 2;
-
-    private EditTextPreference mNamePref;
-    private Preference mPicturePref;
-
-    private IPackageManager mIPm;
-    private PackageManager mPm;
-    private UserManager mUm;
-    private int mUserId;
-    private boolean mNewUser;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        addPreferencesFromResource(R.xml.user_details);
-        Bundle args = getArguments();
-        mNewUser = args == null || args.getInt(EXTRA_USER_ID, -1) == -1;
-        mUserId = mNewUser ? -1 : args.getInt(EXTRA_USER_ID, -1);
-        mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
-        mUm = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
-
-        if (icicle != null && icicle.containsKey(EXTRA_USER_ID)) {
-            mUserId = icicle.getInt(EXTRA_USER_ID);
-            mNewUser = false;
-        }
-
-        if (mUserId == -1) {
-            mUserId = mUm.createUser(getString(R.string.user_new_user_name), 0).id;
-        }
-        mNamePref = (EditTextPreference) findPreference(KEY_USER_NAME);
-        mNamePref.setOnPreferenceChangeListener(this);
-        mPicturePref = findPreference(KEY_USER_PICTURE);
-        mPicturePref.setOnPreferenceClickListener(this);
-        setHasOptionsMenu(true);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        mPm = getActivity().getPackageManager();
-        if (mUserId >= 0) {
-            initExistingUser();
-        } else {
-            initNewUser();
-        }
-    }
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putInt(EXTRA_USER_ID, mUserId);
-    }
-
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        if (mUserId == 0) {
-            return;
-        }
-        MenuItem addAccountItem = menu.add(0, MENU_REMOVE_USER, 0,
-                mNewUser ? R.string.user_discard_user_menu : R.string.user_remove_user_menu);
-        addAccountItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
-                | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        final int itemId = item.getItemId();
-        if (itemId == MENU_REMOVE_USER) {
-            onRemoveUserClicked();
-            return true;
-        } else {
-            return super.onOptionsItemSelected(item);
-        }
-    }
-
-    private void initExistingUser() {
-        List<UserInfo> users = mUm.getUsers();
-        UserInfo foundUser = null;
-        for (UserInfo user : users) {
-            if (user.id == mUserId) {
-                foundUser = user;
-                break;
-            }
-        }
-        if (foundUser != null) {
-            mNamePref.setSummary(foundUser.name);
-            mNamePref.setText(foundUser.name);
-            if (foundUser.iconPath != null) {
-                setPhotoId(foundUser.iconPath);
-            }
-        }
-    }
-
-    private void initNewUser() {
-        // TODO: Check if there's already a "New user" and localize
-        mNamePref.setText(getString(R.string.user_new_user_name));
-        mNamePref.setSummary(getString(R.string.user_new_user_name));
-    }
-
-    private void onRemoveUserClicked() {
-        if (mNewUser) {
-            removeUserNow();
-        } else {
-            showDialog(DIALOG_CONFIRM_REMOVE);
-        }
-    }
-
-    private void removeUserNow() {
-        mUm.removeUser(mUserId);
-        finish();
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        if (preference instanceof CheckBoxPreference) {
-            String packageName = preference.getKey();
-            int newState = ((Boolean) newValue) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
-                    : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
-            try {
-                mIPm.setApplicationEnabledSetting(packageName, newState, 0, mUserId);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to change enabled state of package " + packageName
-                        + " for user " + mUserId);
-            }
-        } else if (preference == mNamePref) {
-            String name = (String) newValue;
-            if (TextUtils.isEmpty(name)) {
-                return false;
-            }
-            mUm.setUserName(mUserId, (String) newValue);
-            mNamePref.setSummary((String) newValue);
-        }
-        return true;
-    }
-
-    @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)
-                    .setPositiveButton(android.R.string.ok,
-                        new DialogInterface.OnClickListener() {
-                            public void onClick(DialogInterface dialog, int which) {
-                                removeUserNow();
-                            }
-                    })
-                    .setNegativeButton(android.R.string.cancel, null)
-                    .create();
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public boolean onPreferenceClick(Preference preference) {
-        if (preference == mPicturePref) {
-            Intent intent = new Intent();
-            intent.setType("image/*");
-            intent.setAction(Intent.ACTION_GET_CONTENT);
-
-            startActivityForResult(intent, RESULT_PICK_IMAGE);
-        }
-        return false;
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (resultCode != Activity.RESULT_OK) {
-            return;
-        }
-        switch (requestCode) {
-        case RESULT_PICK_IMAGE:
-            if (data.getData() != null) {
-                Uri imageUri = data.getData();
-                System.err.println("imageUri = " + imageUri);
-                cropImage(imageUri);
-            }
-            break;
-        case RESULT_CROP_IMAGE:
-            saveCroppedImage(data);
-            break;
-        }
-    }
-
-    private void cropImage(Uri imageUri) {
-        final Uri inputPhotoUri = imageUri;
-        Intent intent = new Intent("com.android.camera.action.CROP");
-        intent.setDataAndType(inputPhotoUri, "image/*");
-        intent.putExtra("crop", "true");
-        intent.putExtra("aspectX", 1);
-        intent.putExtra("aspectY", 1);
-        intent.putExtra("outputX", 96);
-        intent.putExtra("outputY", 96);
-        intent.putExtra("return-data", true);
-        startActivityForResult(intent, RESULT_CROP_IMAGE);
-    }
-
-    private void saveCroppedImage(Intent data) {
-        if (data.hasExtra("data")) {
-            Bitmap bitmap = (Bitmap) data.getParcelableExtra("data");
-            ParcelFileDescriptor fd = mUm.setUserIcon(mUserId);
-            if (fd != null) {
-                bitmap.compress(CompressFormat.PNG, 100,
-                        new ParcelFileDescriptor.AutoCloseOutputStream(fd));
-                setPhotoId(mUm.getUserInfo(mUserId).iconPath);
-            }
-        }
-    }
-
-    private void setPhotoId(String realPath) {
-        Drawable d = Drawable.createFromPath(realPath);
-        if (d == null) return;
-        mPicturePref.setIcon(d);
-    }
-}
diff --git a/src/com/android/settings/users/UserPreference.java b/src/com/android/settings/users/UserPreference.java
new file mode 100644
index 0000000..2ced7ae
--- /dev/null
+++ b/src/com/android/settings/users/UserPreference.java
@@ -0,0 +1,85 @@
+/*
+ * 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 com.android.internal.util.CharSequences;
+import com.android.settings.R;
+
+import android.content.Context;
+import android.os.UserManager;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+public class UserPreference extends Preference {
+
+    public static final int USERID_UNKNOWN = -10;
+
+    private OnClickListener mDeleteClickListener;
+    private int mSerialNumber = -1;
+    private int mUserId = USERID_UNKNOWN;
+
+    public UserPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, USERID_UNKNOWN, false, null);
+    }
+
+    UserPreference(Context context, AttributeSet attrs, int userId, boolean showDelete,
+            OnClickListener deleteListener) {
+        super(context, attrs);
+        if (showDelete) {
+            setWidgetLayoutResource(R.layout.preference_user_delete_widget);
+            mDeleteClickListener = deleteListener;
+        }
+        mUserId = userId;
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        view.setClickable(true);
+        view.setFocusable(true);
+        View deleteView = view.findViewById(R.id.trash_user);
+        if (deleteView != null) {
+            deleteView.setOnClickListener(mDeleteClickListener);
+            deleteView.setTag(this);
+        }
+        super.onBindView(view);
+    }
+
+    public int getSerialNumber() {
+        if (mSerialNumber < 0) {
+            // If the userId is unknown
+            if (mUserId == USERID_UNKNOWN) return Integer.MAX_VALUE;
+            mSerialNumber = ((UserManager) getContext().getSystemService(Context.USER_SERVICE))
+                    .getUserSerialNumber(mUserId);
+            if (mSerialNumber < 0) return mUserId;
+        }
+        return mSerialNumber;
+    }
+
+    public int getUserId() {
+        return mUserId;
+    }
+
+    public int compareTo(Preference another) {
+        if (another instanceof UserPreference) {
+            return getSerialNumber() > ((UserPreference) another).getSerialNumber() ? 1 : -1;
+        } else {
+            return 1;
+        }
+    }
+}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index e530493..7369a92 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -16,52 +16,170 @@
 
 package com.android.settings.users;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 import android.os.UserManager;
+import android.preference.EditTextPreference;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceActivity;
 import android.preference.PreferenceGroup;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Profile;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
 
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
 
 public class UserSettings extends SettingsPreferenceFragment
-        implements OnPreferenceClickListener {
+        implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener,
+        Preference.OnPreferenceChangeListener {
 
+    private static final String TAG = "UserSettings";
+
+    private static final String KEY_USER_NICKNAME = "user_nickname";
     private static final String KEY_USER_LIST = "user_list";
+    private static final String KEY_USER_ME = "user_me";
+
     private static final int MENU_ADD_USER = Menu.FIRST;
+    private static final int MENU_REMOVE_USER = Menu.FIRST+1;
+
+    private static final int DIALOG_CONFIRM_REMOVE = 1;
+    private static final int DIALOG_ADD_USER = 2;
+
+    private static final int MESSAGE_UPDATE_LIST = 1;
+
+    private static final int[] USER_DRAWABLES = {
+        R.drawable.ic_user,
+        R.drawable.ic_user_cyan,
+        R.drawable.ic_user_green,
+        R.drawable.ic_user_purple,
+        R.drawable.ic_user_red,
+        R.drawable.ic_user_yellow
+    };
+
+    private static final String[] CONTACT_PROJECTION = new String[] {
+        Phone._ID,                      // 0
+        Phone.DISPLAY_NAME,             // 1
+    };
 
     private PreferenceGroup mUserListCategory;
+    private Preference mMePreference;
+    private EditTextPreference mNicknamePreference;
+    private int mRemovingUserId = -1;
+    private boolean mAddingUser;
+
+    private final Object mUserLock = new Object();
+    private UserManager mUserManager;
+    private boolean mProfileChanged;
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MESSAGE_UPDATE_LIST:
+                updateUserList();
+                break;
+            }
+        }
+    };
+
+    private ContentObserver mProfileObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange) {
+            mProfileChanged = true;
+        }
+    };
+
+    private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
+        }
+    };
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
+        mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
         addPreferencesFromResource(R.xml.user_settings);
         mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
-
+        mMePreference = (Preference) findPreference(KEY_USER_ME);
+        mMePreference.setOnPreferenceClickListener(this);
+        if (UserHandle.myUserId() != UserHandle.USER_OWNER) {
+            mMePreference.setSummary(null);
+        }
+        mNicknamePreference = (EditTextPreference) findPreference(KEY_USER_NICKNAME);
+        mNicknamePreference.setOnPreferenceChangeListener(this);
+        mNicknamePreference.setSummary(mUserManager.getUserInfo(UserHandle.myUserId()).name);
+        loadProfile(false);
         setHasOptionsMenu(true);
+        // Register to watch for profile changes
+        getActivity().getContentResolver().registerContentObserver(
+                ContactsContract.Profile.CONTENT_URI, false, mProfileObserver);
+        getActivity().registerReceiver(mUserChangeReceiver,
+                new IntentFilter(Intent.ACTION_USER_REMOVED));
     }
 
     @Override
     public void onResume() {
         super.onResume();
+        if (mProfileChanged) {
+            loadProfile(true);
+            mProfileChanged = false;
+        }
         updateUserList();
     }
 
     @Override
+    public void onDestroy() {
+        super.onDestroy();
+        getActivity().getContentResolver().unregisterContentObserver(mProfileObserver);
+        getActivity().unregisterReceiver(mUserChangeReceiver);
+    }
+
+    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        MenuItem addAccountItem = menu.add(0, MENU_ADD_USER, 0, R.string.user_add_user_menu);
-        addAccountItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
-                | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+        if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
+            MenuItem addUserItem = menu.add(0, MENU_ADD_USER, 0, R.string.user_add_user_menu);
+            addUserItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
+                    | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+        } else {
+            MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, 0, R.string.user_remove_user_menu);
+            removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
+                    | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+        }
     }
 
     @Override
@@ -70,52 +188,270 @@
         if (itemId == MENU_ADD_USER) {
             onAddUserClicked();
             return true;
+        } else if (itemId == MENU_REMOVE_USER) {
+            onRemoveUserClicked(UserHandle.myUserId());
+            return true;
         } else {
             return super.onOptionsItemSelected(item);
         }
     }
 
+    private void loadProfile(boolean force) {
+        UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
+        if (force || user.iconPath == null || user.iconPath.equals("")) {
+            assignProfilePhoto(user);
+        }
+        String profileName = getProfileName();
+        mMePreference.setTitle(profileName);
+    }
+
     private void onAddUserClicked() {
-        ((PreferenceActivity) getActivity()).startPreferencePanel(
-                UserDetailsSettings.class.getName(), null, R.string.user_details_title,
-                null, this, 0);
+        synchronized (mUserLock) {
+            if (mRemovingUserId == -1 && !mAddingUser) {
+                showDialog(DIALOG_ADD_USER);
+                setOnDismissListener(this);
+            }
+        }
+    }
+
+    private void onRemoveUserClicked(int userId) {
+        synchronized (mUserLock) {
+            if (mRemovingUserId == -1 && !mAddingUser) {
+                mRemovingUserId = userId;
+                showDialog(DIALOG_CONFIRM_REMOVE);
+                setOnDismissListener(this);
+            }
+        }
+    }
+
+    @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)
+                    .setPositiveButton(android.R.string.ok,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int which) {
+                                removeUserNow();
+                            }
+                    })
+                    .setNegativeButton(android.R.string.cancel, null)
+                    .create();
+            case DIALOG_ADD_USER:
+                return new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.user_add_user_title)
+                .setMessage(R.string.user_add_user_message)
+                .setPositiveButton(android.R.string.ok,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            addUserNow();
+                        }
+                })
+                .setNegativeButton(android.R.string.cancel, null)
+                .create();
+            default:
+                return null;
+        }
+    }
+
+    private void removeUserNow() {
+        if (mRemovingUserId == UserHandle.myUserId()) {
+            removeThisUser();
+        } else {
+            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();
+        }
+    }
+
+    private void removeThisUser() {
+        // TODO:
+        Toast.makeText(getActivity(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
+
+        synchronized (mUserLock) {
+            mRemovingUserId = -1;
+        }
+    }
+
+    private void addUserNow() {
+        synchronized (mUserLock) {
+            mAddingUser = true;
+            updateUserList();
+            new Thread() {
+                public void run() {
+                    // Could take a few seconds
+                    UserInfo user = mUserManager.createUser(
+                            getActivity().getResources().getString(R.string.user_new_user_name), 0);
+                    if (user != null) {
+                        assignDefaultPhoto(user);
+                    }
+                    synchronized (mUserLock) {
+                        mAddingUser = false;
+                        mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
+                    }
+                }
+            }.start();
+        }
     }
 
     private void updateUserList() {
-        List<UserInfo> users = ((UserManager) getActivity().getSystemService(Context.USER_SERVICE))
-                .getUsers();
+        List<UserInfo> users = mUserManager.getUsers();
 
         mUserListCategory.removeAll();
+        mUserListCategory.setOrderingAsAdded(false);
+
         for (UserInfo user : users) {
-            Preference pref = new Preference(getActivity());
-            pref.setTitle(user.name);
-            pref.setOnPreferenceClickListener(this);
-            pref.setKey("id=" + user.id);
-            if (user.iconPath != null) {
-                setPhotoId(pref, user.iconPath);
+            Preference pref;
+            if (user.id == UserHandle.myUserId()) {
+                pref = mMePreference;
+            } else {
+                pref = new UserPreference(getActivity(), null, user.id,
+                        UserHandle.myUserId() == UserHandle.USER_OWNER, this);
+                pref.setOnPreferenceClickListener(this);
+                pref.setKey("id=" + user.id);
+                mUserListCategory.addPreference(pref);
+                if (user.id == UserHandle.USER_OWNER) {
+                    pref.setSummary(R.string.user_owner);
+                }
+                pref.setTitle(user.name);
             }
+            if (user.iconPath != null) {
+                setPhotoId(pref, user);
+            }
+        }
+        // Add a temporary entry for the user being created
+        if (mAddingUser) {
+            Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN,
+                    false, null);
+            pref.setEnabled(false);
+            pref.setTitle(R.string.user_new_user_name);
+            pref.setSummary(R.string.user_adding_new_user);
+            pref.setIcon(R.drawable.ic_user);
             mUserListCategory.addPreference(pref);
         }
     }
 
-    private void setPhotoId(Preference pref, String realPath) {
-        Drawable d = Drawable.createFromPath(realPath);
+    /* TODO: Put this in an AsyncTask */
+    private void assignProfilePhoto(final UserInfo user) {
+        // If the contact is "me", then use my local profile photo. Otherwise, build a
+        // uri to get the avatar of the contact.
+        Uri contactUri = Profile.CONTENT_URI;
+
+        InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
+                    getActivity().getContentResolver(),
+                    contactUri, true);
+        // If there's no profile photo, assign a default avatar
+        if (avatarDataStream == null) {
+            assignDefaultPhoto(user);
+            setPhotoId(mMePreference, user);
+            return;
+        }
+
+        ParcelFileDescriptor fd = mUserManager.setUserIcon(user.id);
+        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);
+            }
+            os.close();
+            avatarDataStream.close();
+        } catch (IOException ioe) {
+            Log.e(TAG, "Error copying profile photo " + ioe);
+        }
+
+        setPhotoId(mMePreference, 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;
+        }
+
+        try {
+            if (cursor.moveToFirst()) {
+                return cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+            }
+        } finally {
+            cursor.close();
+        }
+        return null;
+    }
+
+    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));
+        }
+    }
+
+    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);
     }
 
+    private void setUserName(String name) {
+        mUserManager.setUserName(UserHandle.myUserId(), name);
+        mNicknamePreference.setSummary(name);
+    }
+
     @Override
     public boolean onPreferenceClick(Preference pref) {
-        String sid = pref.getKey();
-        if (sid != null && sid.startsWith("id=")) {
-            int id = Integer.parseInt(sid.substring(3));
-            Bundle args = new Bundle();
-            args.putInt(UserDetailsSettings.EXTRA_USER_ID, id);
-            ((PreferenceActivity) getActivity()).startPreferencePanel(
-                    UserDetailsSettings.class.getName(),
-                    args, 0, pref.getTitle(), this, 0);
+        if (pref == mMePreference) {
+            Intent editProfile = new Intent(Intent.ACTION_EDIT);
+            editProfile.setData(ContactsContract.Profile.CONTENT_URI);
+            startActivity(editProfile);
+        }
+        return false;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v.getTag() instanceof UserPreference) {
+            int userId = ((UserPreference) v.getTag()).getUserId();
+            onRemoveUserClicked(userId);
+        }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        synchronized (mUserLock) {
+            mAddingUser = false;
+            mRemovingUserId = -1;
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mNicknamePreference) {
+            String value = (String) newValue;
+            if (preference == mNicknamePreference && value != null
+                    && value.length() > 0) {
+                setUserName(value);
+            }
             return true;
         }
         return false;
     }
+
 }