diff --git a/res/values/strings.xml b/res/values/strings.xml index cc2bb44e6bc..072b8441507 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4187,6 +4187,8 @@ Active Not active + + Not set up Owner @@ -4194,14 +4196,26 @@ 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. + 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. + + Set up user now? + + Make sure the person is available to take the tablet and set up their space + + Set up now + + Not now Remove user New user + + Delete yourself? Remove user? + + 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? Are you sure you want to remove the user and all associated data from the device? diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 777a712938c..ee1bfeeb6a8 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -23,25 +23,41 @@ import android.content.pm.ApplicationInfo; 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.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.ParcelFileDescriptor; +import android.os.ParcelFileDescriptor.AutoCloseOutputStream; import android.os.SystemProperties; +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,55 @@ public class Utils { 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); + 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) { } + } + return false; + } + + 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/users/ProfileUpdateReceiver.java b/src/com/android/settings/users/ProfileUpdateReceiver.java index 5513608bf8b..88daa5899c2 100644 --- a/src/com/android/settings/users/ProfileUpdateReceiver.java +++ b/src/com/android/settings/users/ProfileUpdateReceiver.java @@ -19,64 +19,45 @@ package com.android.settings.users; 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 com.android.settings.Utils; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; /** * 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 28fe4c10e26..11948b42f3f 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; @@ -36,6 +37,7 @@ import android.os.Bundle; 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,6 +48,7 @@ import android.provider.ContactsContract; 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.view.Menu; import android.view.MenuInflater; @@ -54,8 +57,10 @@ import android.view.View; 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; @@ -77,8 +82,10 @@ public class UserSettings extends SettingsPreferenceFragment 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,6 +105,7 @@ public class UserSettings extends SettingsPreferenceFragment private Preference mMePreference; private EditTextPreference mNicknamePreference; private int mRemovingUserId = -1; + private int mAddedUserId = 0; private boolean mAddingUser; private boolean mProfileExists; @@ -111,6 +119,9 @@ public class UserSettings extends SettingsPreferenceFragment case MESSAGE_UPDATE_LIST: updateUserList(); break; + case MESSAGE_SETUP_USER: + onUserCreated(msg.arg1); + break; } } }; @@ -136,7 +147,8 @@ public class UserSettings extends SettingsPreferenceFragment } 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, @@ -229,13 +241,22 @@ public class UserSettings extends SettingsPreferenceFragment } } + 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 +277,19 @@ public class UserSettings extends SettingsPreferenceFragment }) .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; } @@ -279,11 +313,12 @@ public class UserSettings extends SettingsPreferenceFragment } 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,12 +337,22 @@ public class UserSettings extends SettingsPreferenceFragment 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() { List users = mUserManager.getUsers(); @@ -318,6 +363,8 @@ public class UserSettings extends SettingsPreferenceFragment Preference pref; 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); @@ -347,29 +394,17 @@ public class UserSettings extends SettingsPreferenceFragment } 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) {