diff --git a/res/drawable/ic_default_user.png b/res/drawable/ic_default_user.png new file mode 100644 index 00000000000..ddf797fc9da Binary files /dev/null and b/res/drawable/ic_default_user.png differ diff --git a/res/drawable/ic_user.png b/res/drawable/ic_user.png new file mode 100644 index 00000000000..dc4c390f0da Binary files /dev/null and b/res/drawable/ic_user.png differ diff --git a/res/drawable/ic_user_cyan.png b/res/drawable/ic_user_cyan.png new file mode 100644 index 00000000000..c21261582e2 Binary files /dev/null and b/res/drawable/ic_user_cyan.png differ diff --git a/res/drawable/ic_user_green.png b/res/drawable/ic_user_green.png new file mode 100644 index 00000000000..ca09f8534e4 Binary files /dev/null and b/res/drawable/ic_user_green.png differ diff --git a/res/drawable/ic_user_purple.png b/res/drawable/ic_user_purple.png new file mode 100644 index 00000000000..b7bdeb290d8 Binary files /dev/null and b/res/drawable/ic_user_purple.png differ diff --git a/res/drawable/ic_user_red.png b/res/drawable/ic_user_red.png new file mode 100644 index 00000000000..c4b4e298afa Binary files /dev/null and b/res/drawable/ic_user_red.png differ diff --git a/res/drawable/ic_user_yellow.png b/res/drawable/ic_user_yellow.png new file mode 100644 index 00000000000..c46838cd34e Binary files /dev/null and b/res/drawable/ic_user_yellow.png differ diff --git a/res/layout/preference_user_delete_widget.xml b/res/layout/preference_user_delete_widget.xml new file mode 100644 index 00000000000..994b77a0556 --- /dev/null +++ b/res/layout/preference_user_delete_widget.xml @@ -0,0 +1,41 @@ + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index ba3f3865fb5..36eb09d9e26 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4165,39 +4165,34 @@ Users - Users + Other users Add user + + Active + + Not active + + Owner + + Nickname + + Add new user + + 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. - - - - - Edit details - - User information - - Name - - Content restrictions - - Require PIN - - Content rating - - System apps - - Installed apps - - Discard Remove user - Pesky kid + New user Remove user? Are you sure you want to remove the user and all associated data from the device? + + Adding new user\u2026 + + Delete user Show notifications diff --git a/res/xml/user_details.xml b/res/xml/user_details.xml deleted file mode 100644 index f36fd4584f7..00000000000 --- a/res/xml/user_details.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - diff --git a/res/xml/user_settings.xml b/res/xml/user_settings.xml index 95bc7034bb4..acb7c0f7387 100644 --- a/res/xml/user_settings.xml +++ b/res/xml/user_settings.xml @@ -18,6 +18,19 @@ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" android:title="@string/user_settings_title"> + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index d5a90f645d7..6f2002a9c3b 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -107,14 +107,13 @@ public class Settings extends PreferenceActivity 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 mHeaderIndexMap = new HashMap(); @@ -129,11 +128,6 @@ public class Settings extends PreferenceActivity 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 @@ public class Settings extends PreferenceActivity 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 518c6b621c9..00000000000 --- 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 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 00000000000..2ced7ae6639 --- /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 e5304931040..7369a9255a0 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 @@ public class UserSettings extends SettingsPreferenceFragment 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 users = ((UserManager) getActivity().getSystemService(Context.USER_SERVICE)) - .getUsers(); + List 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; } + }