1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 5 import static android.os.Build.VERSION_CODES.LOLLIPOP; 6 import static android.os.Build.VERSION_CODES.M; 7 import static android.os.Build.VERSION_CODES.N; 8 import static android.os.Build.VERSION_CODES.N_MR1; 9 import static android.os.Build.VERSION_CODES.P; 10 import static android.os.Build.VERSION_CODES.Q; 11 import static android.os.Build.VERSION_CODES.R; 12 import static android.os.Build.VERSION_CODES.S; 13 import static android.os.Build.VERSION_CODES.TIRAMISU; 14 import static android.os.UserManager.USER_TYPE_FULL_GUEST; 15 import static android.os.UserManager.USER_TYPE_FULL_RESTRICTED; 16 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; 17 import static org.robolectric.shadow.api.Shadow.invokeConstructor; 18 import static org.robolectric.util.ReflectionHelpers.ClassParameter.from; 19 import static org.robolectric.util.reflector.Reflector.reflector; 20 21 import android.Manifest.permission; 22 import android.accounts.Account; 23 import android.annotation.UserIdInt; 24 import android.app.Application; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.PackageManager; 28 import android.content.pm.UserInfo; 29 import android.graphics.Bitmap; 30 import android.os.Build; 31 import android.os.Bundle; 32 import android.os.IUserManager; 33 import android.os.PersistableBundle; 34 import android.os.Process; 35 import android.os.UserHandle; 36 import android.os.UserManager; 37 import com.google.common.base.Preconditions; 38 import com.google.common.collect.BiMap; 39 import com.google.common.collect.HashBiMap; 40 import com.google.common.collect.ImmutableList; 41 import java.util.ArrayList; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Set; 47 import org.robolectric.RuntimeEnvironment; 48 import org.robolectric.annotation.HiddenApi; 49 import org.robolectric.annotation.Implementation; 50 import org.robolectric.annotation.Implements; 51 import org.robolectric.annotation.RealObject; 52 import org.robolectric.annotation.Resetter; 53 import org.robolectric.shadow.api.Shadow; 54 import org.robolectric.util.reflector.Accessor; 55 import org.robolectric.util.reflector.Direct; 56 import org.robolectric.util.reflector.ForType; 57 58 /** Robolectric implementation of {@link android.os.UserManager}. */ 59 @Implements(value = UserManager.class, minSdk = JELLY_BEAN_MR1) 60 public class ShadowUserManager { 61 62 /** 63 * The default user ID user for secondary user testing, when the ID is not otherwise specified. 64 */ 65 public static final int DEFAULT_SECONDARY_USER_ID = 10; 66 67 private static final int DEFAULT_MAX_SUPPORTED_USERS = 1; 68 69 public static final int FLAG_PRIMARY = UserInfo.FLAG_PRIMARY; 70 public static final int FLAG_ADMIN = UserInfo.FLAG_ADMIN; 71 public static final int FLAG_GUEST = UserInfo.FLAG_GUEST; 72 public static final int FLAG_RESTRICTED = UserInfo.FLAG_RESTRICTED; 73 public static final int FLAG_DEMO = UserInfo.FLAG_DEMO; 74 public static final int FLAG_MANAGED_PROFILE = UserInfo.FLAG_MANAGED_PROFILE; 75 public static final int FLAG_PROFILE = UserInfo.FLAG_PROFILE; 76 public static final int FLAG_FULL = UserInfo.FLAG_FULL; 77 public static final int FLAG_SYSTEM = UserInfo.FLAG_SYSTEM; 78 79 private static int maxSupportedUsers = DEFAULT_MAX_SUPPORTED_USERS; 80 private static boolean isMultiUserSupported = false; 81 private static boolean isHeadlessSystemUserMode = false; 82 83 private final Object lock = new Object(); 84 85 @RealObject private UserManager realObject; 86 private UserManagerState userManagerState; 87 private Boolean managedProfile; 88 private Boolean cloneProfile; 89 private boolean userUnlocked = true; 90 private boolean isSystemUser = true; 91 92 /** 93 * Holds whether or not a managed profile can be unlocked. If a profile is not in this map, it is 94 * assume it can be unlocked. 95 */ 96 private String seedAccountName; 97 98 private String seedAccountType; 99 private PersistableBundle seedAccountOptions; 100 101 private Context context; 102 private boolean enforcePermissions; 103 private int userSwitchability = UserManager.SWITCHABILITY_STATUS_OK; 104 105 private final Set<Account> userAccounts = new HashSet<>(); 106 107 /** 108 * Global UserManager state. Shared across {@link UserManager}s created in different {@link 109 * Context}s. 110 */ 111 static class UserManagerState { 112 private final Map<Integer, Integer> userPidMap = new HashMap<>(); 113 /** Holds the serial numbers for all users and profiles, indexed by UserHandle.id */ 114 private final BiMap<Integer, Long> userSerialNumbers = HashBiMap.create(); 115 /** Holds all UserStates, indexed by UserHandle.id */ 116 private final Map<Integer, UserState> userState = new HashMap<>(); 117 /** Holds the UserInfo for all registered users and profiles, indexed by UserHandle.id */ 118 private final Map<Integer, UserInfo> userInfoMap = new HashMap<>(); 119 /** 120 * Each user holds a list of UserHandles of assocated profiles and user itself. User is indexed 121 * by UserHandle.id. See UserManager.getProfiles(userId). 122 */ 123 private final Map<Integer, List<UserHandle>> userProfilesListMap = new HashMap<>(); 124 125 private final Map<Integer, Bundle> userRestrictions = new HashMap<>(); 126 private final Map<String, Bundle> applicationRestrictions = new HashMap<>(); 127 private final Map<Integer, Boolean> profileIsLocked = new HashMap<>(); 128 private final Map<Integer, Bitmap> userIcon = new HashMap<>(); 129 130 private int nextUserId = DEFAULT_SECONDARY_USER_ID; 131 132 // TODO: use UserInfo.FLAG_MAIN when available 133 private static final int FLAG_MAIN = 0x00004000; 134 UserManagerState()135 public UserManagerState() { 136 int id = UserHandle.USER_SYSTEM; 137 String name = "system_user"; 138 int flags = UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN | FLAG_MAIN; 139 140 userSerialNumbers.put(id, (long) id); 141 // Start the user as shut down. 142 userState.put(id, UserState.STATE_SHUTDOWN); 143 144 // Update UserInfo regardless if was added or not 145 userInfoMap.put(id, new UserInfo(id, name, flags)); 146 userProfilesListMap.put(id, new ArrayList<>()); 147 // getUserProfiles() includes user's handle 148 userProfilesListMap.get(id).add(new UserHandle(id)); 149 userPidMap.put(id, Process.myUid()); 150 } 151 } 152 153 @Implementation __constructor__(Context context, IUserManager service)154 protected void __constructor__(Context context, IUserManager service) { 155 this.context = context; 156 invokeConstructor( 157 UserManager.class, 158 realObject, 159 from(Context.class, context), 160 from(IUserManager.class, service)); 161 162 userManagerState = ShadowApplication.getInstance().getUserManagerState(); 163 } 164 165 /** 166 * Compared to real Android, there is no check that the package name matches the application 167 * package name and the method returns instantly. 168 * 169 * @see #setApplicationRestrictions(String, Bundle) 170 */ 171 @Implementation(minSdk = JELLY_BEAN_MR2) getApplicationRestrictions(String packageName)172 protected Bundle getApplicationRestrictions(String packageName) { 173 Bundle bundle = userManagerState.applicationRestrictions.get(packageName); 174 return bundle != null ? bundle : new Bundle(); 175 } 176 177 /** Sets the value returned by {@link UserManager#getApplicationRestrictions(String)}. */ setApplicationRestrictions(String packageName, Bundle restrictions)178 public void setApplicationRestrictions(String packageName, Bundle restrictions) { 179 userManagerState.applicationRestrictions.put(packageName, restrictions); 180 } 181 182 /** 183 * Adds a profile associated for the user that the calling process is running on. 184 * 185 * <p>The user is assigned an arbitrary unique serial number. 186 * 187 * @return the user's serial number 188 * @deprecated use either addUser() or addProfile() 189 */ 190 @Deprecated addUserProfile(UserHandle userHandle)191 public long addUserProfile(UserHandle userHandle) { 192 addProfile(UserHandle.myUserId(), userHandle.getIdentifier(), "", 0); 193 return userManagerState.userSerialNumbers.get(userHandle.getIdentifier()); 194 } 195 196 @Implementation(minSdk = LOLLIPOP) getUserProfiles()197 protected List<UserHandle> getUserProfiles() { 198 ImmutableList.Builder<UserHandle> builder = new ImmutableList.Builder<>(); 199 List<UserHandle> profiles = userManagerState.userProfilesListMap.get(UserHandle.myUserId()); 200 if (profiles != null) { 201 return builder.addAll(profiles).build(); 202 } 203 for (List<UserHandle> profileList : userManagerState.userProfilesListMap.values()) { 204 if (profileList.contains(Process.myUserHandle())) { 205 return builder.addAll(profileList).build(); 206 } 207 } 208 return ImmutableList.of(Process.myUserHandle()); 209 } 210 211 /** 212 * If any profiles have been added using {@link #addProfile}, return those profiles. 213 * 214 * <p>Otherwise follow real android behaviour. 215 */ 216 @Implementation(minSdk = LOLLIPOP) getProfiles(int userHandle)217 protected List<UserInfo> getProfiles(int userHandle) { 218 if (userManagerState.userProfilesListMap.containsKey(userHandle)) { 219 ArrayList<UserInfo> infos = new ArrayList<>(); 220 for (UserHandle profileHandle : userManagerState.userProfilesListMap.get(userHandle)) { 221 infos.add(userManagerState.userInfoMap.get(profileHandle.getIdentifier())); 222 } 223 return infos; 224 } 225 return reflector(UserManagerReflector.class, realObject).getProfiles(userHandle); 226 } 227 228 @Implementation(minSdk = R) getEnabledProfiles()229 protected List<UserHandle> getEnabledProfiles() { 230 ArrayList<UserHandle> userHandles = new ArrayList<>(); 231 for (UserHandle profileHandle : getAllProfiles()) { 232 if (userManagerState.userInfoMap.get(profileHandle.getIdentifier()).isEnabled()) { 233 userHandles.add(profileHandle); 234 } 235 } 236 237 return userHandles; 238 } 239 240 @Implementation(minSdk = R) getAllProfiles()241 protected List<UserHandle> getAllProfiles() { 242 ArrayList<UserHandle> userHandles = new ArrayList<>(); 243 if (userManagerState.userProfilesListMap.containsKey(context.getUserId())) { 244 userHandles.addAll(userManagerState.userProfilesListMap.get(context.getUserId())); 245 return userHandles; 246 } 247 248 userHandles.add(UserHandle.of(context.getUserId())); 249 return userHandles; 250 } 251 252 @Implementation(minSdk = LOLLIPOP) getProfileParent(int userId)253 protected UserInfo getProfileParent(int userId) { 254 if (enforcePermissions && !hasManageUsersPermission()) { 255 throw new SecurityException("Requires MANAGE_USERS permission"); 256 } 257 UserInfo profile = getUserInfo(userId); 258 if (profile == null) { 259 return null; 260 } 261 int parentUserId = profile.profileGroupId; 262 if (parentUserId == userId || parentUserId == UserInfo.NO_PROFILE_GROUP_ID) { 263 return null; 264 } else { 265 return getUserInfo(parentUserId); 266 } 267 } 268 269 @Implementation(minSdk = R) createProfile(String name, String userType, Set<String> disallowedPackages)270 protected UserHandle createProfile(String name, String userType, Set<String> disallowedPackages) { 271 int flags = getDefaultUserTypeFlags(userType); 272 flags |= FLAG_PROFILE; // assume createProfile used with a profile userType 273 if (enforcePermissions && !hasManageUsersPermission() && !hasCreateUsersPermission()) { 274 throw new SecurityException( 275 "You either need MANAGE_USERS or CREATE_USERS " 276 + "permission to create an user with flags: " 277 + flags); 278 } 279 280 if (userManagerState.userInfoMap.size() >= getMaxSupportedUsers()) { 281 return null; 282 } 283 284 int profileId = userManagerState.nextUserId++; 285 addProfile(context.getUserId(), profileId, name, flags); 286 userManagerState.userInfoMap.get(profileId).userType = userType; 287 return UserHandle.of(profileId); 288 } 289 getDefaultUserTypeFlags(String userType)290 private static int getDefaultUserTypeFlags(String userType) { 291 switch (userType) { 292 case UserManager.USER_TYPE_PROFILE_MANAGED: 293 return FLAG_PROFILE | FLAG_MANAGED_PROFILE; 294 case UserManager.USER_TYPE_FULL_SECONDARY: 295 return FLAG_FULL; 296 case UserManager.USER_TYPE_FULL_GUEST: 297 return FLAG_FULL | FLAG_GUEST; 298 case UserManager.USER_TYPE_FULL_DEMO: 299 return FLAG_FULL | FLAG_DEMO; 300 case UserManager.USER_TYPE_FULL_RESTRICTED: 301 return FLAG_FULL | FLAG_RESTRICTED; 302 case UserManager.USER_TYPE_FULL_SYSTEM: 303 return FLAG_FULL | FLAG_SYSTEM; 304 case UserManager.USER_TYPE_SYSTEM_HEADLESS: 305 return FLAG_SYSTEM; 306 default: 307 return 0; 308 } 309 } 310 311 /** Add a profile to be returned by {@link #getProfiles(int)}. */ addProfile( int userHandle, int profileUserHandle, String profileName, int profileFlags)312 public void addProfile( 313 int userHandle, int profileUserHandle, String profileName, int profileFlags) { 314 UserInfo profileUserInfo = new UserInfo(profileUserHandle, profileName, profileFlags); 315 addProfile(userHandle, profileUserHandle, profileUserInfo); 316 } 317 318 /** Add a profile to be returned by {@link #getProfiles(int)}. */ addProfile(int userHandle, int profileUserHandle, UserInfo profileUserInfo)319 public void addProfile(int userHandle, int profileUserHandle, UserInfo profileUserInfo) { 320 // Don't override serial number set by setSerialNumberForUser() 321 if (!userManagerState.userSerialNumbers.containsKey(profileUserHandle)) { 322 // use UserHandle id as serial number unless setSerialNumberForUser() is used 323 userManagerState.userSerialNumbers.put(profileUserHandle, (long) profileUserHandle); 324 } 325 if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) { 326 profileUserInfo.profileGroupId = userHandle; 327 UserInfo parentUserInfo = getUserInfo(userHandle); 328 if (parentUserInfo != null) { 329 parentUserInfo.profileGroupId = userHandle; 330 } 331 } 332 userManagerState.userInfoMap.put(profileUserHandle, profileUserInfo); 333 // Insert profile to the belonging user's userProfilesList 334 userManagerState.userProfilesListMap.putIfAbsent(userHandle, new ArrayList<>()); 335 List<UserHandle> list = userManagerState.userProfilesListMap.get(userHandle); 336 UserHandle handle = new UserHandle(profileUserHandle); 337 if (!list.contains(handle)) { 338 list.add(handle); 339 } 340 } 341 342 /** Setter for {@link UserManager#isUserUnlocked()} */ setUserUnlocked(boolean userUnlocked)343 public void setUserUnlocked(boolean userUnlocked) { 344 this.userUnlocked = userUnlocked; 345 } 346 347 @Implementation(minSdk = N) isUserUnlocked()348 protected boolean isUserUnlocked() { 349 return userUnlocked; 350 } 351 352 /** @see #setUserState(UserHandle, UserState) */ 353 @Implementation(minSdk = 24) isUserUnlocked(UserHandle handle)354 protected boolean isUserUnlocked(UserHandle handle) { 355 checkPermissions(); 356 UserState state = userManagerState.userState.get(handle.getIdentifier()); 357 358 return state == UserState.STATE_RUNNING_UNLOCKED; 359 } 360 361 /** 362 * If permissions are enforced (see {@link #enforcePermissionChecks(boolean)}) and the application 363 * doesn't have the {@link android.Manifest.permission#MANAGE_USERS} permission, throws a {@link 364 * SecurityManager} exception. 365 * 366 * @return false by default, or the value specified via {@link #setManagedProfile(boolean)} 367 * @see #enforcePermissionChecks(boolean) 368 * @see #setManagedProfile(boolean) 369 */ 370 @Implementation(minSdk = LOLLIPOP) isManagedProfile()371 protected boolean isManagedProfile() { 372 if (enforcePermissions && !hasManageUsersPermission()) { 373 throw new SecurityException( 374 "You need MANAGE_USERS permission to: check if specified user a " 375 + "managed profile outside your profile group"); 376 } 377 378 if (managedProfile != null) { 379 return managedProfile; 380 } 381 382 if (RuntimeEnvironment.getApiLevel() >= R) { 383 return isManagedProfile(context.getUserId()); 384 } 385 386 return false; 387 } 388 389 /** 390 * If permissions are enforced (see {@link #enforcePermissionChecks(boolean)}) and the application 391 * doesn't have the {@link android.Manifest.permission#MANAGE_USERS} permission, throws a {@link 392 * SecurityManager} exception. 393 * 394 * @return true if the profile added has FLAG_MANAGED_PROFILE 395 * @see #enforcePermissionChecks(boolean) 396 * @see #addProfile(int, int, String, int) 397 * @see #addUser(int, String, int) 398 */ 399 @Implementation(minSdk = N) isManagedProfile(int userHandle)400 protected boolean isManagedProfile(int userHandle) { 401 if (enforcePermissions && !hasManageUsersPermission()) { 402 throw new SecurityException( 403 "You need MANAGE_USERS permission to: check if specified user a " 404 + "managed profile outside your profile group"); 405 } 406 UserInfo info = getUserInfo(userHandle); 407 return info != null && ((info.flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE); 408 } 409 enforcePermissionChecks(boolean enforcePermissions)410 public void enforcePermissionChecks(boolean enforcePermissions) { 411 this.enforcePermissions = enforcePermissions; 412 } 413 414 /** Setter for {@link UserManager#isManagedProfile()}. */ setManagedProfile(boolean managedProfile)415 public void setManagedProfile(boolean managedProfile) { 416 this.managedProfile = managedProfile; 417 } 418 419 /** 420 * If permissions are enforced (see {@link #enforcePermissionChecks(boolean)}) and the application 421 * doesn't have the {@link android.Manifest.permission#MANAGE_USERS} permission, throws a {@link 422 * SecurityManager} exception. 423 * 424 * @return true if the user is clone, or the value specified via {@link #setCloneProfile(boolean)} 425 * @see #enforcePermissionChecks(boolean) 426 * @see #setCloneProfile(boolean) 427 */ 428 @Implementation(minSdk = S) isCloneProfile()429 protected boolean isCloneProfile() { 430 if (enforcePermissions && !hasManageUsersPermission()) { 431 throw new SecurityException("You need MANAGE_USERS permission to: check isCloneProfile"); 432 } 433 434 if (cloneProfile != null) { 435 return cloneProfile; 436 } 437 438 UserInfo info = getUserInfo(context.getUserId()); 439 return info != null && info.isCloneProfile(); 440 } 441 442 /** Setter for {@link UserManager#isCloneProfile()}. */ setCloneProfile(boolean cloneProfile)443 public void setCloneProfile(boolean cloneProfile) { 444 this.cloneProfile = cloneProfile; 445 } 446 447 @Implementation(minSdk = R) isProfile()448 protected boolean isProfile() { 449 if (enforcePermissions && !hasManageUsersPermission()) { 450 throw new SecurityException( 451 "You need INTERACT_ACROSS_USERS or MANAGE_USERS permission to: check isProfile"); 452 } 453 454 return getUserInfo(context.getUserId()).isProfile(); 455 } 456 457 @Implementation(minSdk = R) isUserOfType(String userType)458 protected boolean isUserOfType(String userType) { 459 if (enforcePermissions && !hasManageUsersPermission()) { 460 throw new SecurityException("You need MANAGE_USERS permission to: check user type"); 461 } 462 463 UserInfo info = getUserInfo(context.getUserId()); 464 return info != null && info.userType != null && info.userType.equals(userType); 465 } 466 467 @Implementation(minSdk = R) isSameProfileGroup(UserHandle user, UserHandle otherUser)468 protected boolean isSameProfileGroup(UserHandle user, UserHandle otherUser) { 469 if (enforcePermissions && !hasManageUsersPermission()) { 470 throw new SecurityException( 471 "You need MANAGE_USERS permission to: check if in the same profile group"); 472 } 473 474 UserInfo userInfo = userManagerState.userInfoMap.get(user.getIdentifier()); 475 UserInfo otherUserInfo = userManagerState.userInfoMap.get(otherUser.getIdentifier()); 476 477 if (userInfo == null 478 || otherUserInfo == null 479 || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID 480 || otherUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { 481 return false; 482 } 483 484 return userInfo.profileGroupId == otherUserInfo.profileGroupId; 485 } 486 487 @Implementation(minSdk = LOLLIPOP) hasUserRestriction(String restrictionKey, UserHandle userHandle)488 protected boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { 489 synchronized (lock) { 490 Bundle bundle = userManagerState.userRestrictions.get(userHandle.getIdentifier()); 491 return bundle != null && bundle.getBoolean(restrictionKey); 492 } 493 } 494 495 /** 496 * Shadows UserManager.setUserRestriction() API. This allows UserManager.hasUserRestriction() to 497 * return meaningful results in test environment; thus, allowing test to verify the invoking of 498 * UserManager.setUserRestriction(). 499 */ 500 @Implementation(minSdk = JELLY_BEAN_MR2) setUserRestriction(String key, boolean value, UserHandle userHandle)501 protected void setUserRestriction(String key, boolean value, UserHandle userHandle) { 502 Bundle bundle = getUserRestrictionsForUser(userHandle); 503 synchronized (lock) { 504 bundle.putBoolean(key, value); 505 } 506 } 507 508 @Implementation(minSdk = JELLY_BEAN_MR2) setUserRestriction(String key, boolean value)509 protected void setUserRestriction(String key, boolean value) { 510 setUserRestriction(key, value, Process.myUserHandle()); 511 } 512 513 /** 514 * @deprecated When possible, please use the real Android framework API {@link 515 * UserManager#setUserRestriction()}. 516 */ 517 @Deprecated setUserRestriction(UserHandle userHandle, String restrictionKey, boolean value)518 public void setUserRestriction(UserHandle userHandle, String restrictionKey, boolean value) { 519 setUserRestriction(restrictionKey, value, userHandle); 520 } 521 522 /** Removes all user restrictions set of a user identified by {@code userHandle}. */ clearUserRestrictions(UserHandle userHandle)523 public void clearUserRestrictions(UserHandle userHandle) { 524 userManagerState.userRestrictions.remove(userHandle.getIdentifier()); 525 } 526 527 @Implementation(minSdk = JELLY_BEAN_MR2) getUserRestrictions(UserHandle userHandle)528 protected Bundle getUserRestrictions(UserHandle userHandle) { 529 return new Bundle(getUserRestrictionsForUser(userHandle)); 530 } 531 getUserRestrictionsForUser(UserHandle userHandle)532 private Bundle getUserRestrictionsForUser(UserHandle userHandle) { 533 synchronized (lock) { 534 Bundle bundle = userManagerState.userRestrictions.get(userHandle.getIdentifier()); 535 if (bundle == null) { 536 bundle = new Bundle(); 537 userManagerState.userRestrictions.put(userHandle.getIdentifier(), bundle); 538 } 539 return bundle; 540 } 541 } 542 543 /** 544 * @see #addProfile(int, int, String, int) 545 * @see #addUser(int, String, int) 546 */ 547 @Implementation getSerialNumberForUser(UserHandle userHandle)548 protected long getSerialNumberForUser(UserHandle userHandle) { 549 Long result = userManagerState.userSerialNumbers.get(userHandle.getIdentifier()); 550 return result == null ? -1L : result; 551 } 552 553 /** 554 * {@link #addUser} uses UserHandle for serialNumber. setSerialNumberForUser() allows assigning an 555 * arbitary serialNumber. Some test use serialNumber!=0 as secondary user check, so it's necessary 556 * to "fake" the serialNumber to a non-zero value. 557 */ setSerialNumberForUser(UserHandle userHandle, long serialNumber)558 public void setSerialNumberForUser(UserHandle userHandle, long serialNumber) { 559 userManagerState.userSerialNumbers.put(userHandle.getIdentifier(), serialNumber); 560 } 561 562 /** 563 * @see #addProfile(int, int, String, int) 564 * @see #addUser(int, String, int) 565 */ 566 @Implementation getUserForSerialNumber(long serialNumber)567 protected UserHandle getUserForSerialNumber(long serialNumber) { 568 Integer userHandle = userManagerState.userSerialNumbers.inverse().get(serialNumber); 569 return userHandle == null ? null : new UserHandle(userHandle); 570 } 571 572 /** 573 * @see #addProfile(int, int, String, int) 574 * @see #addUser(int, String, int) 575 */ 576 @Implementation getUserSerialNumber(@serIdInt int userHandle)577 protected int getUserSerialNumber(@UserIdInt int userHandle) { 578 Long result = userManagerState.userSerialNumbers.get(userHandle); 579 return result != null ? result.intValue() : -1; 580 } 581 getUserName(@serIdInt int userHandle)582 private String getUserName(@UserIdInt int userHandle) { 583 UserInfo user = getUserInfo(userHandle); 584 return user == null ? "" : user.name; 585 } 586 587 /** 588 * Returns the name of the user. 589 * 590 * <p>On real Android, if a UserHandle.USER_SYSTEM user is found but does not have a name, it will 591 * return a name like "Owner". In Robolectric, the USER_SYSTEM user always has a name. 592 */ 593 @Implementation(minSdk = Q) getUserName()594 protected String getUserName() { 595 if (RuntimeEnvironment.getApiLevel() >= R) { 596 return getUserName(context.getUserId()); 597 } 598 599 return getUserName(UserHandle.myUserId()); 600 } 601 602 @Implementation(minSdk = R) setUserName(String name)603 protected void setUserName(String name) { 604 if (enforcePermissions && !hasManageUsersPermission()) { 605 throw new SecurityException("You need MANAGE_USERS permission to: rename users"); 606 } 607 UserInfo user = getUserInfo(context.getUserId()); 608 user.name = name; 609 } 610 611 @Implementation(minSdk = Q) getUserIcon()612 protected Bitmap getUserIcon() { 613 if (enforcePermissions 614 && !hasManageUsersPermission() 615 && !hasGetAccountsPrivilegedPermission()) { 616 throw new SecurityException( 617 "You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED permissions to: get user icon"); 618 } 619 620 int userId = UserHandle.myUserId(); 621 if (RuntimeEnvironment.getApiLevel() >= R) { 622 userId = context.getUserId(); 623 } 624 625 return userManagerState.userIcon.get(userId); 626 } 627 628 @Implementation(minSdk = Q) setUserIcon(Bitmap icon)629 protected void setUserIcon(Bitmap icon) { 630 if (enforcePermissions && !hasManageUsersPermission()) { 631 throw new SecurityException("You need MANAGE_USERS permission to: update users"); 632 } 633 634 int userId = UserHandle.myUserId(); 635 if (RuntimeEnvironment.getApiLevel() >= R) { 636 userId = context.getUserId(); 637 } 638 639 userManagerState.userIcon.put(userId, icon); 640 } 641 642 /** @return user id for given user serial number. */ 643 @HiddenApi 644 @Implementation(minSdk = JELLY_BEAN_MR1) 645 @UserIdInt getUserHandle(int serialNumber)646 protected int getUserHandle(int serialNumber) { 647 Integer userHandle = userManagerState.userSerialNumbers.inverse().get((long) serialNumber); 648 return userHandle == null ? -1 : userHandle; 649 } 650 651 @HiddenApi 652 @Implementation(minSdk = R) getUserHandles(boolean excludeDying)653 protected List<UserHandle> getUserHandles(boolean excludeDying) { 654 ArrayList<UserHandle> userHandles = new ArrayList<>(); 655 for (int id : userManagerState.userSerialNumbers.keySet()) { 656 userHandles.addAll(userManagerState.userProfilesListMap.get(id)); 657 } 658 return userHandles; 659 } 660 661 @HiddenApi 662 @Implementation(minSdk = JELLY_BEAN_MR1) getMaxSupportedUsers()663 protected static int getMaxSupportedUsers() { 664 return maxSupportedUsers; 665 } 666 setMaxSupportedUsers(int maxSupportedUsers)667 public void setMaxSupportedUsers(int maxSupportedUsers) { 668 ShadowUserManager.maxSupportedUsers = maxSupportedUsers; 669 } 670 hasManageUsersPermission()671 private boolean hasManageUsersPermission() { 672 return context 673 .getPackageManager() 674 .checkPermission(permission.MANAGE_USERS, context.getPackageName()) 675 == PackageManager.PERMISSION_GRANTED; 676 } 677 hasCreateUsersPermission()678 private boolean hasCreateUsersPermission() { 679 return context 680 .getPackageManager() 681 .checkPermission(permission.CREATE_USERS, context.getPackageName()) 682 == PackageManager.PERMISSION_GRANTED; 683 } 684 hasModifyQuietModePermission()685 private boolean hasModifyQuietModePermission() { 686 return context 687 .getPackageManager() 688 .checkPermission(permission.MODIFY_QUIET_MODE, context.getPackageName()) 689 == PackageManager.PERMISSION_GRANTED; 690 } 691 hasGetAccountsPrivilegedPermission()692 private boolean hasGetAccountsPrivilegedPermission() { 693 return context 694 .getPackageManager() 695 .checkPermission(permission.GET_ACCOUNTS_PRIVILEGED, context.getPackageName()) 696 == PackageManager.PERMISSION_GRANTED; 697 } 698 checkPermissions()699 private void checkPermissions() { 700 // TODO Ensure permisions 701 // throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS 702 // permission " 703 // + "to: check " + name);throw new SecurityException(); 704 } 705 706 /** @return false by default, or the value specified via {@link #setIsDemoUser(boolean)} */ 707 @Implementation(minSdk = N_MR1) isDemoUser()708 protected boolean isDemoUser() { 709 return getUserInfo(UserHandle.myUserId()).isDemo(); 710 } 711 712 /** 713 * Sets that the current user is a demo user; controls the return value of {@link 714 * UserManager#isDemoUser()}. 715 * 716 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a demo user 717 * instead of changing default user flags. 718 */ 719 @Deprecated setIsDemoUser(boolean isDemoUser)720 public void setIsDemoUser(boolean isDemoUser) { 721 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 722 if (isDemoUser) { 723 userInfo.flags |= UserInfo.FLAG_DEMO; 724 } else { 725 userInfo.flags &= ~UserInfo.FLAG_DEMO; 726 } 727 } 728 729 /** @return 'true' by default, or the value specified via {@link #setIsSystemUser(boolean)} */ 730 @Implementation(minSdk = M) isSystemUser()731 protected boolean isSystemUser() { 732 if (isSystemUser == false) { 733 return false; 734 } else { 735 return reflector(UserManagerReflector.class, realObject).isSystemUser(); 736 } 737 } 738 739 /** 740 * Sets that the current user is the system user; controls the return value of {@link 741 * UserManager#isSystemUser()}. 742 * 743 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a system user 744 * instead of changing default user flags. 745 */ 746 @Deprecated setIsSystemUser(boolean isSystemUser)747 public void setIsSystemUser(boolean isSystemUser) { 748 this.isSystemUser = isSystemUser; 749 } 750 751 /** 752 * Sets that the current user is the primary user; controls the return value of {@link 753 * UserManager#isPrimaryUser()}. 754 * 755 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a primary user 756 * instead of changing default user flags. 757 */ 758 @Deprecated setIsPrimaryUser(boolean isPrimaryUser)759 public void setIsPrimaryUser(boolean isPrimaryUser) { 760 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 761 if (isPrimaryUser) { 762 userInfo.flags |= UserInfo.FLAG_PRIMARY; 763 } else { 764 userInfo.flags &= ~UserInfo.FLAG_PRIMARY; 765 } 766 } 767 768 /** @return 'false' by default, or the value specified via {@link #setIsLinkedUser(boolean)} */ 769 @Implementation(minSdk = JELLY_BEAN_MR2) isLinkedUser()770 protected boolean isLinkedUser() { 771 return isRestrictedProfile(); 772 } 773 774 /** 775 * Sets that the current user is the linked user; controls the return value of {@link 776 * UserManager#isLinkedUser()}. 777 * 778 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a linked user 779 * instead of changing default user flags. 780 */ 781 @Deprecated setIsLinkedUser(boolean isLinkedUser)782 public void setIsLinkedUser(boolean isLinkedUser) { 783 setIsRestrictedProfile(isLinkedUser); 784 } 785 786 /** 787 * Returns 'false' by default, or the value specified via {@link 788 * #setIsRestrictedProfile(boolean)}. 789 */ 790 @Implementation(minSdk = P) isRestrictedProfile()791 protected boolean isRestrictedProfile() { 792 return getUserInfo(UserHandle.myUserId()).isRestricted(); 793 } 794 795 /** 796 * Sets this process running under a restricted profile; controls the return value of {@link 797 * UserManager#isRestrictedProfile()}. 798 * 799 * @deprecated use {@link ShadowUserManager#addUser()} instead 800 */ 801 @Deprecated setIsRestrictedProfile(boolean isRestrictedProfile)802 public void setIsRestrictedProfile(boolean isRestrictedProfile) { 803 if (RuntimeEnvironment.getApiLevel() >= R) { 804 setUserType(isRestrictedProfile ? USER_TYPE_FULL_RESTRICTED : USER_TYPE_FULL_SECONDARY); 805 return; 806 } 807 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 808 if (isRestrictedProfile) { 809 userInfo.flags |= UserInfo.FLAG_RESTRICTED; 810 } else { 811 userInfo.flags &= ~UserInfo.FLAG_RESTRICTED; 812 } 813 } 814 815 /** 816 * Sets that the current user is the guest user; controls the return value of {@link 817 * UserManager#isGuestUser()}. 818 * 819 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a guest user 820 * instead of changing default user flags. 821 */ 822 @Deprecated setIsGuestUser(boolean isGuestUser)823 public void setIsGuestUser(boolean isGuestUser) { 824 if (RuntimeEnvironment.getApiLevel() >= R) { 825 setUserType(isGuestUser ? USER_TYPE_FULL_GUEST : USER_TYPE_FULL_SECONDARY); 826 return; 827 } 828 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 829 if (isGuestUser) { 830 userInfo.flags |= UserInfo.FLAG_GUEST; 831 } else { 832 userInfo.flags &= ~UserInfo.FLAG_GUEST; 833 } 834 } 835 setIsUserEnabled(int userId, boolean enabled)836 public void setIsUserEnabled(int userId, boolean enabled) { 837 UserInfo userInfo = getUserInfo(userId); 838 if (enabled) { 839 userInfo.flags &= ~UserInfo.FLAG_DISABLED; 840 } else { 841 userInfo.flags |= UserInfo.FLAG_DISABLED; 842 } 843 } 844 845 /** @see #setUserState(UserHandle, UserState) */ 846 @Implementation isUserRunning(UserHandle handle)847 protected boolean isUserRunning(UserHandle handle) { 848 checkPermissions(); 849 UserState state = userManagerState.userState.get(handle.getIdentifier()); 850 851 if (state == UserState.STATE_RUNNING_LOCKED 852 || state == UserState.STATE_RUNNING_UNLOCKED 853 || state == UserState.STATE_RUNNING_UNLOCKING) { 854 return true; 855 } else { 856 return false; 857 } 858 } 859 860 /** @see #setUserState(UserHandle, UserState) */ 861 @Implementation isUserRunningOrStopping(UserHandle handle)862 protected boolean isUserRunningOrStopping(UserHandle handle) { 863 checkPermissions(); 864 UserState state = userManagerState.userState.get(handle.getIdentifier()); 865 866 if (state == UserState.STATE_RUNNING_LOCKED 867 || state == UserState.STATE_RUNNING_UNLOCKED 868 || state == UserState.STATE_RUNNING_UNLOCKING 869 || state == UserState.STATE_STOPPING) { 870 return true; 871 } else { 872 return false; 873 } 874 } 875 876 /** @see #setUserState(UserHandle, UserState) */ 877 @Implementation(minSdk = R) isUserUnlockingOrUnlocked(UserHandle handle)878 protected boolean isUserUnlockingOrUnlocked(UserHandle handle) { 879 checkPermissions(); 880 UserState state = userManagerState.userState.get(handle.getIdentifier()); 881 882 return state == UserState.STATE_RUNNING_UNLOCKING || state == UserState.STATE_RUNNING_UNLOCKED; 883 } 884 885 /** 886 * Describes the current state of the user. State can be set using {@link 887 * #setUserState(UserHandle, UserState)}. 888 */ 889 public enum UserState { 890 // User is first coming up. 891 STATE_BOOTING, 892 // User is in the locked state. 893 STATE_RUNNING_LOCKED, 894 // User is in the unlocking state. 895 STATE_RUNNING_UNLOCKING, 896 // User is in the running state. 897 STATE_RUNNING_UNLOCKED, 898 // User is in the initial process of being stopped. 899 STATE_STOPPING, 900 // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN. 901 STATE_SHUTDOWN 902 } 903 904 /** 905 * Sets the current state for a given user, see {@link UserManager#isUserRunning(UserHandle)} and 906 * {@link UserManager#isUserRunningOrStopping(UserHandle)} 907 */ setUserState(UserHandle handle, UserState state)908 public void setUserState(UserHandle handle, UserState state) { 909 userManagerState.userState.put(handle.getIdentifier(), state); 910 } 911 912 /** 913 * Query whether the quiet mode is enabled for a managed profile. 914 * 915 * <p>This method checks whether the user handle corresponds to a managed profile, and then query 916 * its state. When quiet, the user is not running. 917 */ 918 @Implementation(minSdk = N) isQuietModeEnabled(UserHandle userHandle)919 protected boolean isQuietModeEnabled(UserHandle userHandle) { 920 // Return false if this is not a managed profile (this is the OS's behavior). 921 if (!isManagedProfileWithoutPermission(userHandle)) { 922 return false; 923 } 924 925 UserInfo info = getUserInfo(userHandle.getIdentifier()); 926 return (info.flags & UserInfo.FLAG_QUIET_MODE) == UserInfo.FLAG_QUIET_MODE; 927 } 928 929 /** 930 * Request the quiet mode. 931 * 932 * <p>This will succeed unless {@link #setProfileIsLocked(UserHandle, boolean)} is called with 933 * {@code true} for the managed profile, in which case it will always fail. 934 */ 935 @Implementation(minSdk = Q) requestQuietModeEnabled(boolean enableQuietMode, UserHandle userHandle)936 protected boolean requestQuietModeEnabled(boolean enableQuietMode, UserHandle userHandle) { 937 if (enforcePermissions && !hasManageUsersPermission() && !hasModifyQuietModePermission()) { 938 throw new SecurityException("Requires MANAGE_USERS or MODIFY_QUIET_MODE permission"); 939 } 940 Preconditions.checkArgument(isManagedProfileWithoutPermission(userHandle)); 941 int userProfileHandle = userHandle.getIdentifier(); 942 UserInfo info = getUserInfo(userHandle.getIdentifier()); 943 if (enableQuietMode) { 944 userManagerState.userState.put(userProfileHandle, UserState.STATE_SHUTDOWN); 945 info.flags |= UserInfo.FLAG_QUIET_MODE; 946 } else { 947 if (userManagerState.profileIsLocked.getOrDefault(userProfileHandle, false)) { 948 return false; 949 } 950 userManagerState.userState.put(userProfileHandle, UserState.STATE_RUNNING_UNLOCKED); 951 info.flags &= ~UserInfo.FLAG_QUIET_MODE; 952 } 953 954 if (enableQuietMode) { 955 sendQuietModeBroadcast(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, userHandle); 956 } else { 957 sendQuietModeBroadcast(Intent.ACTION_MANAGED_PROFILE_AVAILABLE, userHandle); 958 sendQuietModeBroadcast(Intent.ACTION_MANAGED_PROFILE_UNLOCKED, userHandle); 959 } 960 961 return true; 962 } 963 964 /** 965 * If the current application has the necessary rights, it will receive the background action too. 966 */ sendQuietModeBroadcast(String action, UserHandle profileHandle)967 protected void sendQuietModeBroadcast(String action, UserHandle profileHandle) { 968 Intent intent = new Intent(action); 969 intent.putExtra(Intent.EXTRA_USER, profileHandle); 970 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY); 971 // Send the broadcast to the context-registered receivers. 972 context.sendBroadcast(intent); 973 } 974 975 /** 976 * Check if a profile is managed, not checking permissions. 977 * 978 * <p>This is useful to implement other methods. 979 */ isManagedProfileWithoutPermission(UserHandle userHandle)980 private boolean isManagedProfileWithoutPermission(UserHandle userHandle) { 981 UserInfo info = getUserInfo(userHandle.getIdentifier()); 982 return (info != null && ((info.flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE)); 983 } 984 setProfileIsLocked(UserHandle profileHandle, boolean isLocked)985 public void setProfileIsLocked(UserHandle profileHandle, boolean isLocked) { 986 userManagerState.profileIsLocked.put(profileHandle.getIdentifier(), isLocked); 987 } 988 989 @Implementation(minSdk = Build.VERSION_CODES.N) getSerialNumbersOfUsers(boolean excludeDying)990 protected long[] getSerialNumbersOfUsers(boolean excludeDying) { 991 return getUsers().stream() 992 .map(userInfo -> getUserSerialNumber(userInfo.getUserHandle().getIdentifier())) 993 .mapToLong(l -> l) 994 .toArray(); 995 } 996 997 @Implementation getUsers()998 protected List<UserInfo> getUsers() { 999 return new ArrayList<>(userManagerState.userInfoMap.values()); 1000 } 1001 1002 @Implementation getUserInfo(int userHandle)1003 protected UserInfo getUserInfo(int userHandle) { 1004 return userManagerState.userInfoMap.get(userHandle); 1005 } 1006 1007 /** 1008 * Sets whether switching users is allowed or not; controls the return value of {@link 1009 * UserManager#canSwitchUser()} 1010 * 1011 * @deprecated use {@link #setUserSwitchability} instead 1012 */ 1013 @Deprecated setCanSwitchUser(boolean canSwitchUser)1014 public void setCanSwitchUser(boolean canSwitchUser) { 1015 setUserSwitchability( 1016 canSwitchUser 1017 ? UserManager.SWITCHABILITY_STATUS_OK 1018 : UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED); 1019 } 1020 1021 @Implementation(minSdk = Build.VERSION_CODES.N) getSeedAccountName()1022 protected String getSeedAccountName() { 1023 return seedAccountName; 1024 } 1025 1026 /** Setter for {@link UserManager#getSeedAccountName()} */ setSeedAccountName(String seedAccountName)1027 public void setSeedAccountName(String seedAccountName) { 1028 this.seedAccountName = seedAccountName; 1029 } 1030 1031 @Implementation(minSdk = Build.VERSION_CODES.N) getSeedAccountType()1032 protected String getSeedAccountType() { 1033 return seedAccountType; 1034 } 1035 1036 /** Setter for {@link UserManager#getSeedAccountType()} */ setSeedAccountType(String seedAccountType)1037 public void setSeedAccountType(String seedAccountType) { 1038 this.seedAccountType = seedAccountType; 1039 } 1040 1041 @Implementation(minSdk = Build.VERSION_CODES.N) getSeedAccountOptions()1042 protected PersistableBundle getSeedAccountOptions() { 1043 return seedAccountOptions; 1044 } 1045 1046 /** Setter for {@link UserManager#getSeedAccountOptions()} */ setSeedAccountOptions(PersistableBundle seedAccountOptions)1047 public void setSeedAccountOptions(PersistableBundle seedAccountOptions) { 1048 this.seedAccountOptions = seedAccountOptions; 1049 } 1050 1051 @Implementation(minSdk = Build.VERSION_CODES.N) clearSeedAccountData()1052 protected void clearSeedAccountData() { 1053 seedAccountName = null; 1054 seedAccountType = null; 1055 seedAccountOptions = null; 1056 } 1057 1058 @Implementation(minSdk = JELLY_BEAN_MR1) removeUser(int userHandle)1059 protected boolean removeUser(int userHandle) { 1060 if (!userManagerState.userInfoMap.containsKey(userHandle)) { 1061 return false; 1062 } 1063 userManagerState.userInfoMap.remove(userHandle); 1064 userManagerState.userPidMap.remove(userHandle); 1065 userManagerState.userSerialNumbers.remove(userHandle); 1066 userManagerState.userState.remove(userHandle); 1067 userManagerState.userRestrictions.remove(userHandle); 1068 userManagerState.profileIsLocked.remove(userHandle); 1069 userManagerState.userIcon.remove(userHandle); 1070 userManagerState.userProfilesListMap.remove(userHandle); 1071 // if it's a profile, remove from the belong list in userManagerState.userProfilesListMap 1072 UserHandle profileHandle = new UserHandle(userHandle); 1073 for (List<UserHandle> list : userManagerState.userProfilesListMap.values()) { 1074 if (list.remove(profileHandle)) { 1075 break; 1076 } 1077 } 1078 return true; 1079 } 1080 1081 @Implementation(minSdk = Q) removeUser(UserHandle user)1082 protected boolean removeUser(UserHandle user) { 1083 return removeUser(user.getIdentifier()); 1084 } 1085 1086 @Implementation(minSdk = TIRAMISU) removeUserWhenPossible(UserHandle user, boolean overrideDevicePolicy)1087 protected int removeUserWhenPossible(UserHandle user, boolean overrideDevicePolicy) { 1088 return removeUser(user.getIdentifier()) 1089 ? UserManager.REMOVE_RESULT_REMOVED 1090 : UserManager.REMOVE_RESULT_ERROR_UNKNOWN; 1091 } 1092 1093 @Implementation(minSdk = N) supportsMultipleUsers()1094 protected static boolean supportsMultipleUsers() { 1095 return isMultiUserSupported; 1096 } 1097 1098 /** 1099 * Sets whether multiple users are supported; controls the return value of {@link 1100 * UserManager#supportsMultipleUser}. 1101 */ setSupportsMultipleUsers(boolean isMultiUserSupported)1102 public void setSupportsMultipleUsers(boolean isMultiUserSupported) { 1103 ShadowUserManager.isMultiUserSupported = isMultiUserSupported; 1104 } 1105 1106 /** 1107 * Switches the current user to {@code userHandle}. 1108 * 1109 * @param userId the integer handle of the user, where 0 is the primary user. 1110 */ switchUser(int userId)1111 public void switchUser(int userId) { 1112 if (!userManagerState.userInfoMap.containsKey(userId)) { 1113 throw new UnsupportedOperationException("Must add user before switching to it"); 1114 } 1115 1116 ShadowProcess.setUid(userManagerState.userPidMap.get(userId)); 1117 1118 Application application = (Application) context.getApplicationContext(); 1119 ShadowContextImpl shadowContext = Shadow.extract(application.getBaseContext()); 1120 shadowContext.setUserId(userId); 1121 1122 if (RuntimeEnvironment.getApiLevel() >= R) { 1123 reflector(UserManagerReflector.class, realObject).setUserId(userId); 1124 } 1125 } 1126 1127 /** 1128 * Creates a user with the specified name, userId and flags. 1129 * 1130 * @param id the unique id of user 1131 * @param name name of the user 1132 * @param flags 16 bits for user type. See {@link UserInfo#flags} 1133 * @return a handle to the new user 1134 */ addUser(int id, String name, int flags)1135 public UserHandle addUser(int id, String name, int flags) { 1136 UserHandle userHandle = 1137 id == UserHandle.USER_SYSTEM ? Process.myUserHandle() : new UserHandle(id); 1138 1139 // Don't override serial number set by setSerialNumberForUser() 1140 if (!userManagerState.userSerialNumbers.containsKey(id)) { 1141 // use UserHandle id as serial number unless setSerialNumberForUser() is used 1142 userManagerState.userSerialNumbers.put(id, (long) id); 1143 } 1144 // Start the user as shut down. 1145 userManagerState.userState.put(id, UserState.STATE_SHUTDOWN); 1146 1147 // Update UserInfo regardless if was added or not 1148 userManagerState.userInfoMap.put(id, new UserInfo(id, name, flags)); 1149 if (!userManagerState.userProfilesListMap.containsKey(id)) { 1150 userManagerState.userProfilesListMap.put(id, new ArrayList<>()); 1151 // getUserProfiles() includes user's handle 1152 userManagerState.userProfilesListMap.get(id).add(new UserHandle(id)); 1153 userManagerState.userPidMap.put( 1154 id, 1155 id == UserHandle.USER_SYSTEM 1156 ? Process.myUid() 1157 : id * UserHandle.PER_USER_RANGE + ShadowProcess.getRandomApplicationUid()); 1158 } 1159 return userHandle; 1160 } 1161 1162 /** 1163 * Returns {@code true} by default, or the value specified via {@link #setCanSwitchUser(boolean)}. 1164 */ 1165 @Implementation(minSdk = N, maxSdk = Q) canSwitchUsers()1166 protected boolean canSwitchUsers() { 1167 return getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK; 1168 } 1169 1170 @Implementation(minSdk = Q) getUserSwitchability()1171 protected int getUserSwitchability() { 1172 return userSwitchability; 1173 } 1174 1175 /** Sets the user switchability for all users. */ setUserSwitchability(int switchability)1176 public void setUserSwitchability(int switchability) { 1177 this.userSwitchability = switchability; 1178 } 1179 1180 @Implementation(minSdk = R) hasUserRestrictionForUser(String restrictionKey, UserHandle userHandle)1181 protected boolean hasUserRestrictionForUser(String restrictionKey, UserHandle userHandle) { 1182 return hasUserRestriction(restrictionKey, userHandle); 1183 } 1184 setUserType(String userType)1185 private void setUserType(String userType) { 1186 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 1187 userInfo.userType = userType; 1188 } 1189 1190 /** 1191 * Request the quiet mode. 1192 * 1193 * <p>If {@link #setProfileIsLocked(UserHandle, boolean)} is called with {@code true} for the 1194 * managed profile a request to disable the quiet mode will fail and return {@code false} (i.e. as 1195 * if the user refused to authenticate). Otherwise, the call will always succeed and return {@code 1196 * true}. 1197 * 1198 * <p>This method simply re-directs to {@link ShadowUserManager#requestQuietModeEnabled(boolean, 1199 * UserHandle)} as it already has the desired behavior irrespective of the flag's value. 1200 */ 1201 @Implementation(minSdk = R) requestQuietModeEnabled( boolean enableQuietMode, UserHandle userHandle, int flags)1202 protected boolean requestQuietModeEnabled( 1203 boolean enableQuietMode, UserHandle userHandle, int flags) { 1204 return requestQuietModeEnabled(enableQuietMode, userHandle); 1205 } 1206 1207 @Implementation(minSdk = S) isHeadlessSystemUserMode()1208 protected static boolean isHeadlessSystemUserMode() { 1209 return isHeadlessSystemUserMode; 1210 } 1211 1212 /** Updates headless system user mode. */ setHeadlessSystemUserMode(boolean isEnabled)1213 public static void setHeadlessSystemUserMode(boolean isEnabled) { 1214 ShadowUserManager.isHeadlessSystemUserMode = isEnabled; 1215 } 1216 1217 @Implementation(minSdk = TIRAMISU) getUserRestrictions()1218 protected Bundle getUserRestrictions() { 1219 return getUserRestrictions(UserHandle.getUserHandleForUid(Process.myUid())); 1220 } 1221 1222 @Implementation(minSdk = TIRAMISU) hasUserRestrictionForUser(String restrictionKey, int userId)1223 protected boolean hasUserRestrictionForUser(String restrictionKey, int userId) { 1224 Bundle bundle = getUserRestrictions(UserHandle.getUserHandleForUid(userId)); 1225 return bundle != null && bundle.getBoolean(restrictionKey); 1226 } 1227 1228 @Resetter reset()1229 public static void reset() { 1230 maxSupportedUsers = DEFAULT_MAX_SUPPORTED_USERS; 1231 isMultiUserSupported = false; 1232 isHeadlessSystemUserMode = false; 1233 } 1234 1235 @ForType(UserManager.class) 1236 interface UserManagerReflector { 1237 1238 @Direct getProfiles(int userHandle)1239 List getProfiles(int userHandle); 1240 1241 @Direct isSystemUser()1242 boolean isSystemUser(); 1243 1244 @Accessor("mUserId") setUserId(int userId)1245 void setUserId(int userId); 1246 } 1247 1248 @Implementation(minSdk = TIRAMISU) someUserHasAccount(String accountName, String accountType)1249 protected boolean someUserHasAccount(String accountName, String accountType) { 1250 return userAccounts.contains(new Account(accountName, accountType)); 1251 } 1252 1253 /** Setter for {@link UserManager#someUserHasAccount(String, String)}. */ setSomeUserHasAccount(String accountName, String accountType)1254 public void setSomeUserHasAccount(String accountName, String accountType) { 1255 userAccounts.add(new Account(accountName, accountType)); 1256 } 1257 1258 /** Removes user account set via {@link #setSomeUserHasAccount(String, String)}. */ removeSomeUserHasAccount(String accountName, String accountType)1259 public void removeSomeUserHasAccount(String accountName, String accountType) { 1260 userAccounts.remove(new Account(accountName, accountType)); 1261 } 1262 } 1263