1 /* 2 * Copyright (C) 2018 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 package android.car.user; 17 18 import android.annotation.Nullable; 19 import android.app.ActivityManager; 20 import android.car.settings.CarSettings; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.pm.UserInfo; 26 import android.graphics.Bitmap; 27 import android.graphics.drawable.BitmapDrawable; 28 import android.graphics.drawable.Drawable; 29 import android.os.SystemProperties; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.util.Log; 33 34 import com.android.internal.util.UserIcons; 35 36 import java.util.Iterator; 37 import java.util.List; 38 39 /** 40 * Helper class for {@link UserManager}, this is meant to be used by builds that support 41 * Multi-user model with headless user 0. User 0 is not associated with a real person, and 42 * can not be brought to foreground. 43 * 44 * <p>This class provides method for user management, including creating, removing, adding 45 * and switching users. Methods related to get users will exclude system user by default. 46 * 47 * @hide 48 */ 49 public class CarUserManagerHelper { 50 private static final String TAG = "CarUserManagerHelper"; 51 private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless"; 52 private final Context mContext; 53 private final UserManager mUserManager; 54 private final ActivityManager mActivityManager; 55 private Bitmap mDefaultGuestUserIcon; 56 private OnUsersUpdateListener mUpdateListener; 57 private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { 58 @Override 59 public void onReceive(Context context, Intent intent) { 60 mUpdateListener.onUsersUpdate(); 61 } 62 }; 63 64 public CarUserManagerHelper(Context context) { 65 mContext = context.getApplicationContext(); 66 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 67 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 68 } 69 70 /** 71 * Registers a listener for updates to all users - removing, adding users or changing user info. 72 * 73 * <p> Best practise is to keep one listener per helper. 74 * 75 * @param listener Instance of {@link OnUsersUpdateListener}. 76 */ 77 public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) { 78 if (mUpdateListener != null) { 79 unregisterOnUsersUpdateListener(); 80 } 81 82 mUpdateListener = listener; 83 registerReceiver(); 84 } 85 86 /** 87 * Unregisters on user update listener by unregistering {@code BroadcastReceiver}. 88 */ 89 public void unregisterOnUsersUpdateListener() { 90 unregisterReceiver(); 91 } 92 93 /** 94 * Returns {@code true} if the system is in the headless user 0 model. 95 * 96 * @return {@boolean true} if headless system user. 97 */ 98 public boolean isHeadlessSystemUser() { 99 return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false); 100 } 101 102 /** 103 * Gets UserInfo for the system user. 104 * 105 * @return {@link UserInfo} for the system user. 106 */ 107 public UserInfo getSystemUserInfo() { 108 return mUserManager.getUserInfo(UserHandle.USER_SYSTEM); 109 } 110 111 /** 112 * Gets UserInfo for the current foreground user. 113 * 114 * Concept of foreground user is relevant for the multi-user deployment. Foreground user 115 * corresponds to the currently "logged in" user. 116 * 117 * @return {@link UserInfo} for the foreground user. 118 */ 119 public UserInfo getCurrentForegroundUserInfo() { 120 return mUserManager.getUserInfo(getCurrentForegroundUserId()); 121 } 122 123 /** 124 * @return Id of the current foreground user. 125 */ 126 public int getCurrentForegroundUserId() { 127 return mActivityManager.getCurrentUser(); 128 } 129 130 /** 131 * Gets UserInfo for the user running the caller process. 132 * 133 * <p>Differentiation between foreground user and current process user is relevant for 134 * multi-user deployments. 135 * 136 * <p>Some multi-user aware components (like SystemUI) needs to run a singleton component 137 * in system user. Current process user is always the same for that component, even when 138 * the foreground user changes. 139 * 140 * @return {@link UserInfo} for the user running the current process. 141 */ 142 public UserInfo getCurrentProcessUserInfo() { 143 return mUserManager.getUserInfo(getCurrentProcessUserId()); 144 } 145 146 /** 147 * @return Id for the user running the current process. 148 */ 149 public int getCurrentProcessUserId() { 150 return UserHandle.myUserId(); 151 } 152 153 /** 154 * Gets all the existing foreground users on the system that are not currently running as 155 * the foreground user. 156 * 157 * @return List of {@code UserInfo} for each user that is not the foreground user. 158 */ 159 public List<UserInfo> getAllSwitchableUsers() { 160 if (isHeadlessSystemUser()) { 161 return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId()); 162 } else { 163 return getAllUsersExceptSpecifiedUser(getCurrentForegroundUserId()); 164 } 165 } 166 167 /** 168 * Gets all the users that can be brought to the foreground on the system. 169 * 170 * @return List of {@code UserInfo} for users that associated with a real person. 171 */ 172 public List<UserInfo> getAllUsers() { 173 if (isHeadlessSystemUser()) { 174 return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM); 175 } else { 176 return mUserManager.getUsers(/* excludeDying= */true); 177 } 178 } 179 180 /** 181 * Get all the users except the one with userId passed in. 182 * 183 * @param userId of the user not to be returned. 184 * @return All users other than user with userId. 185 */ 186 private List<UserInfo> getAllUsersExceptSpecifiedUser(int userId) { 187 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true); 188 189 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { 190 UserInfo userInfo = iterator.next(); 191 if (userInfo.id == userId) { 192 // Remove user with userId from the list. 193 iterator.remove(); 194 } 195 } 196 return users; 197 } 198 199 /** 200 * Get all the users except system user and the one with userId passed in. 201 * 202 * @param userId of the user not to be returned. 203 * @return All users other than system user and user with userId. 204 */ 205 private List<UserInfo> getAllUsersExceptSystemUserAndSpecifiedUser(int userId) { 206 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true); 207 208 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { 209 UserInfo userInfo = iterator.next(); 210 if (userInfo.id == userId || userInfo.id == UserHandle.USER_SYSTEM) { 211 // Remove user with userId from the list. 212 iterator.remove(); 213 } 214 } 215 return users; 216 } 217 218 // User information accessors 219 220 /** 221 * Checks whether the user is system user. 222 * 223 * @param userInfo User to check against system user. 224 * @return {@code true} if system user, {@code false} otherwise. 225 */ 226 public boolean isSystemUser(UserInfo userInfo) { 227 return userInfo.id == UserHandle.USER_SYSTEM; 228 } 229 230 /** 231 * Checks whether the user is default user. 232 * 233 * @param userInfo User to check against system user. 234 * @return {@code true} if is default user, {@code false} otherwise. 235 */ 236 public boolean isDefaultUser(UserInfo userInfo) { 237 return userInfo.id == CarSettings.DEFAULT_USER_ID_TO_BOOT_INTO; 238 } 239 240 /** 241 * Checks whether passed in user is the foreground user. 242 * 243 * @param userInfo User to check. 244 * @return {@code true} if foreground user, {@code false} otherwise. 245 */ 246 public boolean isForegroundUser(UserInfo userInfo) { 247 return getCurrentForegroundUserId() == userInfo.id; 248 } 249 250 /** 251 * Checks whether passed in user is the user that's running the current process. 252 * 253 * @param userInfo User to check. 254 * @return {@code true} if user running the process, {@code false} otherwise. 255 */ 256 public boolean isCurrentProcessUser(UserInfo userInfo) { 257 return getCurrentProcessUserId() == userInfo.id; 258 } 259 260 // Foreground user information accessors. 261 262 /** 263 * Checks if the foreground user is a guest user. 264 */ 265 public boolean isForegroundUserGuest() { 266 return getCurrentForegroundUserInfo().isGuest(); 267 } 268 269 /** 270 * Returns whether this user can be removed from the system. 271 * 272 * @param userInfo User to be removed 273 * @return {@code true} if they can be removed, {@code false} otherwise. 274 */ 275 public boolean canUserBeRemoved(UserInfo userInfo) { 276 return !isSystemUser(userInfo); 277 } 278 279 /** 280 * Return whether the foreground user has a restriction. 281 * 282 * @param restriction Restriction to check. Should be a UserManager.* restriction. 283 * @return Whether that restriction exists for the foreground user. 284 */ 285 public boolean foregroundUserHasUserRestriction(String restriction) { 286 return mUserManager.hasUserRestriction( 287 restriction, getCurrentForegroundUserInfo().getUserHandle()); 288 } 289 290 /** 291 * Checks if the foreground user can add new users. 292 */ 293 public boolean canForegroundUserAddUsers() { 294 return !foregroundUserHasUserRestriction(UserManager.DISALLOW_ADD_USER); 295 } 296 297 // Current process user information accessors 298 299 /** 300 * Checks whether this process is running under the system user. 301 */ 302 public boolean isCurrentProcessSystemUser() { 303 return mUserManager.isSystemUser(); 304 } 305 306 /** 307 * Checks if the calling app is running in a demo user. 308 */ 309 public boolean isCurrentProcessDemoUser() { 310 return mUserManager.isDemoUser(); 311 } 312 313 /** 314 * Checks if the calling app is running as a guest user. 315 */ 316 public boolean isCurrentProcessGuestUser() { 317 return mUserManager.isGuestUser(); 318 } 319 320 /** 321 * Check is the calling app is running as a restricted profile user (ie. a LinkedUser). 322 * Restricted profiles are only available when {@link #isHeadlessSystemUser()} is false. 323 */ 324 public boolean isCurrentProcessRestrictedProfileUser() { 325 return mUserManager.isRestrictedProfile(); 326 } 327 328 // Current process user restriction accessors 329 330 /** 331 * Return whether the user running the current process has a restriction. 332 * 333 * @param restriction Restriction to check. Should be a UserManager.* restriction. 334 * @return Whether that restriction exists for the user running the process. 335 */ 336 public boolean isCurrentProcessUserHasRestriction(String restriction) { 337 return mUserManager.hasUserRestriction(restriction); 338 } 339 340 /** 341 * Checks if the current process user can modify accounts. Demo and Guest users cannot modify 342 * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied. 343 */ 344 public boolean canCurrentProcessModifyAccounts() { 345 return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS) 346 && !isCurrentProcessDemoUser() 347 && !isCurrentProcessGuestUser(); 348 } 349 350 /** 351 * Checks if the user running the current process can add new users. 352 */ 353 public boolean canCurrentProcessAddUsers() { 354 return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_ADD_USER); 355 } 356 357 /** 358 * Checks if the user running the current process can remove users. 359 */ 360 public boolean canCurrentProcessRemoveUsers() { 361 return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_REMOVE_USER); 362 } 363 364 /** 365 * Checks if the user running the current process is allowed to switch to another user. 366 */ 367 public boolean canCurrentProcessSwitchUsers() { 368 return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_USER_SWITCH); 369 } 370 371 /** 372 * Creates a new user on the system, the created user would be granted admin role. 373 * 374 * @param userName Name to give to the newly created user. 375 * @return Newly created admin user, null if failed to create a user. 376 */ 377 @Nullable 378 public UserInfo createNewAdminUser(String userName) { 379 UserInfo user = mUserManager.createUser(userName, UserInfo.FLAG_ADMIN); 380 if (user == null) { 381 // Couldn't create user, most likely because there are too many, but we haven't 382 // been able to reload the list yet. 383 Log.w(TAG, "can't create admin user."); 384 return null; 385 } 386 assignDefaultIcon(user); 387 return user; 388 } 389 390 /** 391 * Creates a new restricted user on the system. 392 * 393 * @param userName Name to give to the newly created user. 394 * @return Newly created restricted user, null if failed to create a user. 395 */ 396 @Nullable 397 public UserInfo createNewNonAdminUser(String userName) { 398 UserInfo user = mUserManager.createUser(userName, 0); 399 if (user == null) { 400 // Couldn't create user, most likely because there are too many, but we haven't 401 // been able to reload the list yet. 402 Log.w(TAG, "can't create non-admin user."); 403 return null; 404 } 405 assignDefaultIcon(user); 406 return user; 407 } 408 409 /** 410 * Tries to remove the user that's passed in. System user cannot be removed. 411 * If the user to be removed is user currently running the process, 412 * it switches to the guest user first, and then removes the user. 413 * 414 * @param userInfo User to be removed 415 * @return {@code true} if user is successfully removed, {@code false} otherwise. 416 */ 417 public boolean removeUser(UserInfo userInfo, String guestUserName) { 418 if (isSystemUser(userInfo)) { 419 Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed."); 420 return false; 421 } 422 423 // Not allow to delete the default user for now. Since default user is the one to 424 // boot into. 425 if (isHeadlessSystemUser() && isDefaultUser(userInfo)) { 426 Log.w(TAG, "User " + userInfo.id + " is the default user, could not be removed."); 427 return false; 428 } 429 430 if (userInfo.id == getCurrentForegroundUserId()) { 431 startNewGuestSession(guestUserName); 432 } 433 434 return mUserManager.removeUser(userInfo.id); 435 } 436 437 /** 438 * Switches (logs in) to another user given user id. 439 * 440 * @param id User id to switch to. 441 * @return {@code true} if user switching succeed. 442 */ 443 public boolean switchToUserId(int id) { 444 if (id == UserHandle.USER_SYSTEM && isHeadlessSystemUser()) { 445 // System User doesn't associate with real person, can not be switched to. 446 return false; 447 } 448 return mActivityManager.switchUser(id); 449 } 450 451 /** 452 * Switches (logs in) to another user. 453 * 454 * @param userInfo User to switch to. 455 * @return {@code true} if user switching succeed. 456 */ 457 public boolean switchToUser(UserInfo userInfo) { 458 if (userInfo.id == getCurrentForegroundUserId()) { 459 return false; 460 } 461 462 return switchToUserId(userInfo.id); 463 } 464 465 /** 466 * Creates a new guest session and switches into the guest session. 467 * 468 * @param guestName Username for the guest user. 469 * @return {@code true} if switch to guest user succeed. 470 */ 471 public boolean startNewGuestSession(String guestName) { 472 UserInfo guest = mUserManager.createGuest(mContext, guestName); 473 if (guest == null) { 474 // Couldn't create user, most likely because there are too many, but we haven't 475 // been able to reload the list yet. 476 Log.w(TAG, "can't create user."); 477 return false; 478 } 479 assignDefaultIcon(guest); 480 return switchToUserId(guest.id); 481 } 482 483 /** 484 * Gets a bitmap representing the user's default avatar. 485 * 486 * @param userInfo User whose avatar should be returned. 487 * @return Default user icon 488 */ 489 public Bitmap getUserDefaultIcon(UserInfo userInfo) { 490 return UserIcons.convertToBitmap( 491 UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false)); 492 } 493 494 /** 495 * Gets a bitmap representing the default icon for a Guest user. 496 * 497 * @return Default guest user icon 498 */ 499 public Bitmap getGuestDefaultIcon() { 500 if (mDefaultGuestUserIcon == null) { 501 mDefaultGuestUserIcon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon( 502 mContext.getResources(), UserHandle.USER_NULL, false)); 503 } 504 return mDefaultGuestUserIcon; 505 } 506 507 /** 508 * Gets an icon for the user. 509 * 510 * @param userInfo User for which we want to get the icon. 511 * @return a Bitmap for the icon 512 */ 513 public Bitmap getUserIcon(UserInfo userInfo) { 514 Bitmap picture = mUserManager.getUserIcon(userInfo.id); 515 516 if (picture == null) { 517 return assignDefaultIcon(userInfo); 518 } 519 520 return picture; 521 } 522 523 /** 524 * Method for scaling a Bitmap icon to a desirable size. 525 * 526 * @param icon Bitmap to scale. 527 * @param desiredSize Wanted size for the icon. 528 * @return Drawable for the icon, scaled to the new size. 529 */ 530 public Drawable scaleUserIcon(Bitmap icon, int desiredSize) { 531 Bitmap scaledIcon = Bitmap.createScaledBitmap( 532 icon, desiredSize, desiredSize, true /* filter */); 533 return new BitmapDrawable(mContext.getResources(), scaledIcon); 534 } 535 536 /** 537 * Sets new Username for the user. 538 * 539 * @param user User whose name should be changed. 540 * @param name New username. 541 */ 542 public void setUserName(UserInfo user, String name) { 543 mUserManager.setUserName(user.id, name); 544 } 545 546 private void registerReceiver() { 547 IntentFilter filter = new IntentFilter(); 548 filter.addAction(Intent.ACTION_USER_REMOVED); 549 filter.addAction(Intent.ACTION_USER_ADDED); 550 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 551 filter.addAction(Intent.ACTION_USER_SWITCHED); 552 filter.addAction(Intent.ACTION_USER_STOPPED); 553 filter.addAction(Intent.ACTION_USER_UNLOCKED); 554 mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null); 555 } 556 557 // Assigns a default icon to a user according to the user's id. 558 private Bitmap assignDefaultIcon(UserInfo userInfo) { 559 Bitmap bitmap = userInfo.isGuest() 560 ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo); 561 mUserManager.setUserIcon(userInfo.id, bitmap); 562 return bitmap; 563 } 564 565 private void unregisterReceiver() { 566 mContext.unregisterReceiver(mUserChangeReceiver); 567 } 568 569 /** 570 * Interface for listeners that want to register for receiving updates to changes to the users 571 * on the system including removing and adding users, and changing user info. 572 */ 573 public interface OnUsersUpdateListener { 574 /** 575 * Method that will get called when users list has been changed. 576 */ 577 void onUsersUpdate(); 578 } 579 } 580