UserSettings.java revision 9627a8ea151c1f27e5e9f34592c7b34fea3101c3
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.users; 18 19import android.app.ActivityManagerNative; 20import android.app.AlertDialog; 21import android.app.Dialog; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.pm.UserInfo; 28import android.graphics.Bitmap; 29import android.graphics.BitmapFactory; 30import android.graphics.drawable.BitmapDrawable; 31import android.graphics.drawable.Drawable; 32import android.os.AsyncTask; 33import android.os.Bundle; 34import android.os.Handler; 35import android.os.Message; 36import android.os.RemoteException; 37import android.os.UserHandle; 38import android.os.UserManager; 39import android.preference.Preference; 40import android.preference.Preference.OnPreferenceClickListener; 41import android.preference.PreferenceGroup; 42import android.provider.ContactsContract; 43import android.provider.ContactsContract.Contacts; 44import android.provider.ContactsContract.CommonDataKinds.Phone; 45import android.text.InputType; 46import android.util.Log; 47import android.util.SparseArray; 48import android.view.Menu; 49import android.view.MenuInflater; 50import android.view.MenuItem; 51import android.view.View; 52import android.view.View.OnClickListener; 53import android.widget.EditText; 54 55import com.android.settings.R; 56import com.android.settings.SelectableEditTextPreference; 57import com.android.settings.SettingsPreferenceFragment; 58import com.android.settings.Utils; 59 60import java.util.ArrayList; 61import java.util.List; 62 63public class UserSettings extends SettingsPreferenceFragment 64 implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener, 65 Preference.OnPreferenceChangeListener { 66 67 private static final String TAG = "UserSettings"; 68 69 private static final String KEY_USER_NICKNAME = "user_nickname"; 70 private static final String KEY_USER_LIST = "user_list"; 71 private static final String KEY_USER_ME = "user_me"; 72 73 private static final int MENU_ADD_USER = Menu.FIRST; 74 private static final int MENU_REMOVE_USER = Menu.FIRST+1; 75 76 private static final int DIALOG_CONFIRM_REMOVE = 1; 77 private static final int DIALOG_ADD_USER = 2; 78 private static final int DIALOG_SETUP_USER = 3; 79 80 private static final int MESSAGE_UPDATE_LIST = 1; 81 private static final int MESSAGE_SETUP_USER = 2; 82 83 private static final int[] USER_DRAWABLES = { 84 R.drawable.ic_user, 85 R.drawable.ic_user_cyan, 86 R.drawable.ic_user_green, 87 R.drawable.ic_user_purple, 88 R.drawable.ic_user_red, 89 R.drawable.ic_user_yellow 90 }; 91 92 private PreferenceGroup mUserListCategory; 93 private Preference mMePreference; 94 private SelectableEditTextPreference mNicknamePreference; 95 private int mRemovingUserId = -1; 96 private int mAddedUserId = 0; 97 private boolean mAddingUser; 98 private boolean mProfileExists; 99 100 private final Object mUserLock = new Object(); 101 private UserManager mUserManager; 102 private SparseArray<Drawable> mUserIcons = new SparseArray<Drawable>(); 103 104 private Handler mHandler = new Handler() { 105 @Override 106 public void handleMessage(Message msg) { 107 switch (msg.what) { 108 case MESSAGE_UPDATE_LIST: 109 updateUserList(); 110 break; 111 case MESSAGE_SETUP_USER: 112 onUserCreated(msg.arg1); 113 break; 114 } 115 } 116 }; 117 118 private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { 119 @Override 120 public void onReceive(Context context, Intent intent) { 121 if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) { 122 mRemovingUserId = -1; 123 } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) { 124 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 125 if (userHandle != -1) { 126 mUserIcons.remove(userHandle); 127 } 128 } 129 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 130 } 131 }; 132 133 @Override 134 public void onCreate(Bundle icicle) { 135 super.onCreate(icicle); 136 mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); 137 addPreferencesFromResource(R.xml.user_settings); 138 mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST); 139 mMePreference = (Preference) findPreference(KEY_USER_ME); 140 mMePreference.setOnPreferenceClickListener(this); 141 if (UserHandle.myUserId() != UserHandle.USER_OWNER) { 142 mMePreference.setSummary(null); 143 } 144 mNicknamePreference = (SelectableEditTextPreference) findPreference(KEY_USER_NICKNAME); 145 mNicknamePreference.setOnPreferenceChangeListener(this); 146 mNicknamePreference.getEditText().setInputType( 147 InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_TEXT_FLAG_CAP_WORDS); 148 mNicknamePreference.setInitialSelectionMode( 149 SelectableEditTextPreference.SELECTION_SELECT_ALL); 150 loadProfile(); 151 setHasOptionsMenu(true); 152 IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED); 153 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 154 getActivity().registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, 155 mHandler); 156 } 157 158 @Override 159 public void onResume() { 160 super.onResume(); 161 loadProfile(); 162 updateUserList(); 163 } 164 165 @Override 166 public void onDestroy() { 167 super.onDestroy(); 168 getActivity().unregisterReceiver(mUserChangeReceiver); 169 } 170 171 @Override 172 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 173 if (UserHandle.myUserId() == UserHandle.USER_OWNER) { 174 if (mUserManager.getMaxSupportedUsers() > mUserManager.getUsers(false).size()) { 175 MenuItem addUserItem = menu.add(0, MENU_ADD_USER, 0, R.string.user_add_user_menu); 176 addUserItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM 177 | MenuItem.SHOW_AS_ACTION_WITH_TEXT); 178 } 179 } else { 180 MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, 0, R.string.user_remove_user_menu); 181 removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM 182 | MenuItem.SHOW_AS_ACTION_WITH_TEXT); 183 } 184 super.onCreateOptionsMenu(menu, inflater); 185 } 186 187 @Override 188 public boolean onOptionsItemSelected(MenuItem item) { 189 final int itemId = item.getItemId(); 190 if (itemId == MENU_ADD_USER) { 191 onAddUserClicked(); 192 return true; 193 } else if (itemId == MENU_REMOVE_USER) { 194 onRemoveUserClicked(UserHandle.myUserId()); 195 return true; 196 } else { 197 return super.onOptionsItemSelected(item); 198 } 199 } 200 201 private void loadProfile() { 202 mProfileExists = false; 203 new AsyncTask<Void, Void, String>() { 204 @Override 205 protected void onPostExecute(String result) { 206 finishLoadProfile(result); 207 } 208 209 @Override 210 protected String doInBackground(Void... values) { 211 UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId()); 212 if (user.iconPath == null || user.iconPath.equals("")) { 213 assignProfilePhoto(user); 214 } 215 String profileName = getProfileName(); 216 return profileName; 217 } 218 }.execute(); 219 } 220 221 private void finishLoadProfile(String profileName) { 222 mMePreference.setTitle(profileName); 223 int myUserId = UserHandle.myUserId(); 224 Bitmap b = mUserManager.getUserIcon(myUserId); 225 if (b != null) { 226 Drawable d = new BitmapDrawable(b); 227 mMePreference.setIcon(d); 228 mUserIcons.put(myUserId, d); 229 } 230 } 231 232 private void onAddUserClicked() { 233 synchronized (mUserLock) { 234 if (mRemovingUserId == -1 && !mAddingUser) { 235 showDialog(DIALOG_ADD_USER); 236 setOnDismissListener(this); 237 } 238 } 239 } 240 241 private void onRemoveUserClicked(int userId) { 242 synchronized (mUserLock) { 243 if (mRemovingUserId == -1 && !mAddingUser) { 244 mRemovingUserId = userId; 245 showDialog(DIALOG_CONFIRM_REMOVE); 246 setOnDismissListener(this); 247 } 248 } 249 } 250 251 private void onUserCreated(int userId) { 252 mAddedUserId = userId; 253 showDialog(DIALOG_SETUP_USER); 254 } 255 256 @Override 257 public Dialog onCreateDialog(int dialogId) { 258 switch (dialogId) { 259 case DIALOG_CONFIRM_REMOVE: 260 return new AlertDialog.Builder(getActivity()) 261 .setTitle(UserHandle.myUserId() == mRemovingUserId 262 ? R.string.user_confirm_remove_self_title 263 : R.string.user_confirm_remove_title) 264 .setMessage(UserHandle.myUserId() == mRemovingUserId 265 ? R.string.user_confirm_remove_self_message 266 : R.string.user_confirm_remove_message) 267 .setPositiveButton(android.R.string.ok, 268 new DialogInterface.OnClickListener() { 269 public void onClick(DialogInterface dialog, int which) { 270 removeUserNow(); 271 } 272 }) 273 .setNegativeButton(android.R.string.cancel, null) 274 .create(); 275 case DIALOG_ADD_USER: 276 return new AlertDialog.Builder(getActivity()) 277 .setTitle(R.string.user_add_user_title) 278 .setMessage(R.string.user_add_user_message) 279 .setPositiveButton(android.R.string.ok, 280 new DialogInterface.OnClickListener() { 281 public void onClick(DialogInterface dialog, int which) { 282 addUserNow(); 283 } 284 }) 285 .setNegativeButton(android.R.string.cancel, null) 286 .create(); 287 case DIALOG_SETUP_USER: 288 return new AlertDialog.Builder(getActivity()) 289 .setTitle(R.string.user_setup_dialog_title) 290 .setMessage(R.string.user_setup_dialog_message) 291 .setPositiveButton(R.string.user_setup_button_setup_now, 292 new DialogInterface.OnClickListener() { 293 public void onClick(DialogInterface dialog, int which) { 294 switchUserNow(mAddedUserId); 295 } 296 }) 297 .setNegativeButton(R.string.user_setup_button_setup_later, null) 298 .create(); 299 300 default: 301 return null; 302 } 303 } 304 305 private void removeUserNow() { 306 if (mRemovingUserId == UserHandle.myUserId()) { 307 removeThisUser(); 308 } else { 309 new Thread() { 310 public void run() { 311 synchronized (mUserLock) { 312 mUserManager.removeUser(mRemovingUserId); 313 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 314 } 315 } 316 }.start(); 317 } 318 } 319 320 private void removeThisUser() { 321 try { 322 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER); 323 ((UserManager) getActivity().getSystemService(Context.USER_SERVICE)) 324 .removeUser(UserHandle.myUserId()); 325 } catch (RemoteException re) { 326 Log.e(TAG, "Unable to remove self user"); 327 } 328 } 329 330 private void addUserNow() { 331 synchronized (mUserLock) { 332 mAddingUser = true; 333 updateUserList(); 334 new Thread() { 335 public void run() { 336 // Could take a few seconds 337 UserInfo user = mUserManager.createUser( 338 getActivity().getResources().getString(R.string.user_new_user_name), 0); 339 if (user != null) { 340 assignDefaultPhoto(user); 341 } 342 synchronized (mUserLock) { 343 mAddingUser = false; 344 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 345 mHandler.sendMessage(mHandler.obtainMessage( 346 MESSAGE_SETUP_USER, user.id, user.serialNumber)); 347 } 348 } 349 }.start(); 350 } 351 } 352 353 private void switchUserNow(int userId) { 354 try { 355 ActivityManagerNative.getDefault().switchUser(userId); 356 } catch (RemoteException re) { 357 // Nothing to do 358 } 359 } 360 361 private void updateUserList() { 362 if (getActivity() == null) return; 363 List<UserInfo> users = mUserManager.getUsers(true); 364 365 mUserListCategory.removeAll(); 366 mUserListCategory.setOrderingAsAdded(false); 367 368 final ArrayList<Integer> missingIcons = new ArrayList<Integer>(); 369 for (UserInfo user : users) { 370 Preference pref; 371 if (user.id == mRemovingUserId) { 372 continue; 373 } else if (user.id == UserHandle.myUserId()) { 374 pref = mMePreference; 375 mNicknamePreference.getEditText().setText(user.name); 376 mNicknamePreference.setSummary(user.name); 377 } else { 378 pref = new UserPreference(getActivity(), null, user.id, 379 UserHandle.myUserId() == UserHandle.USER_OWNER, this); 380 pref.setOnPreferenceClickListener(this); 381 pref.setKey("id=" + user.id); 382 mUserListCategory.addPreference(pref); 383 if (user.id == UserHandle.USER_OWNER) { 384 pref.setSummary(R.string.user_owner); 385 } 386 pref.setTitle(user.name); 387 } 388 if (user.iconPath != null) { 389 if (mUserIcons.get(user.id) == null) { 390 missingIcons.add(user.id); 391 pref.setIcon(R.drawable.ic_user); 392 } else { 393 setPhotoId(pref, user); 394 } 395 } 396 } 397 // Add a temporary entry for the user being created 398 if (mAddingUser) { 399 Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN, 400 false, null); 401 pref.setEnabled(false); 402 pref.setTitle(R.string.user_new_user_name); 403 pref.setSummary(R.string.user_adding_new_user); 404 pref.setIcon(R.drawable.ic_user); 405 mUserListCategory.addPreference(pref); 406 } 407 getActivity().invalidateOptionsMenu(); 408 409 // Load the icons 410 if (missingIcons.size() > 0) { 411 loadIconsAsync(missingIcons); 412 } 413 } 414 415 private void loadIconsAsync(List<Integer> missingIcons) { 416 new AsyncTask<List<Integer>, Void, Void>() { 417 @Override 418 protected void onPostExecute(Void result) { 419 updateUserList(); 420 } 421 422 @Override 423 protected Void doInBackground(List<Integer>... values) { 424 if (getActivity() == null) return null; 425 for (int userId : values[0]) { 426 Bitmap bitmap = mUserManager.getUserIcon(userId); 427 Drawable d = new BitmapDrawable(getResources(), bitmap); 428 mUserIcons.append(userId, d); 429 } 430 return null; 431 } 432 }.execute(missingIcons); 433 434 } 435 private void assignProfilePhoto(final UserInfo user) { 436 if (!Utils.copyMeProfilePhoto(getActivity(), user)) { 437 assignDefaultPhoto(user); 438 } 439 } 440 441 private String getProfileName() { 442 String name = Utils.getMeProfileName(getActivity()); 443 if (name != null) { 444 mProfileExists = true; 445 } 446 return name; 447 } 448 449 private void assignDefaultPhoto(UserInfo user) { 450 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 451 USER_DRAWABLES[user.id % USER_DRAWABLES.length]); 452 mUserManager.setUserIcon(user.id, bitmap); 453 } 454 455 private void setPhotoId(Preference pref, UserInfo user) { 456 Drawable d = mUserIcons.get(user.id); // UserUtils.getUserIcon(mUserManager, user); 457 if (d != null) { 458 pref.setIcon(d); 459 } 460 } 461 462 private void setUserName(String name) { 463 mUserManager.setUserName(UserHandle.myUserId(), name); 464 mNicknamePreference.setSummary(name); 465 } 466 467 @Override 468 public boolean onPreferenceClick(Preference pref) { 469 if (pref == mMePreference) { 470 Intent editProfile; 471 if (!mProfileExists) { 472 editProfile = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); 473 // TODO: Make this a proper API 474 editProfile.putExtra("newLocalProfile", true); 475 } else { 476 editProfile = new Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI); 477 } 478 // To make sure that it returns back here when done 479 // TODO: Make this a proper API 480 editProfile.putExtra("finishActivityOnSaveCompleted", true); 481 startActivity(editProfile); 482 } 483 return false; 484 } 485 486 @Override 487 public void onClick(View v) { 488 if (v.getTag() instanceof UserPreference) { 489 int userId = ((UserPreference) v.getTag()).getUserId(); 490 onRemoveUserClicked(userId); 491 } 492 } 493 494 @Override 495 public void onDismiss(DialogInterface dialog) { 496 synchronized (mUserLock) { 497 mAddingUser = false; 498 mRemovingUserId = -1; 499 } 500 } 501 502 @Override 503 public boolean onPreferenceChange(Preference preference, Object newValue) { 504 if (preference == mNicknamePreference) { 505 String value = (String) newValue; 506 if (preference == mNicknamePreference && value != null 507 && value.length() > 0) { 508 setUserName(value); 509 } 510 return true; 511 } 512 return false; 513 } 514 515 @Override 516 public int getHelpResource() { 517 return R.string.help_url_users; 518 } 519} 520