• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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