Home | History | Annotate | Download | only in shadows
      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.N;
      7 import static android.os.Build.VERSION_CODES.N_MR1;
      8 
      9 import android.Manifest.permission;
     10 import android.content.Context;
     11 import android.content.pm.PackageManager;
     12 import android.content.pm.UserInfo;
     13 import android.os.Bundle;
     14 import android.os.IUserManager;
     15 import android.os.Process;
     16 import android.os.UserHandle;
     17 import android.os.UserManager;
     18 
     19 import com.google.common.collect.BiMap;
     20 import com.google.common.collect.HashBiMap;
     21 import com.google.common.collect.ImmutableList;
     22 
     23 import org.robolectric.annotation.Implementation;
     24 import org.robolectric.annotation.Implements;
     25 
     26 import java.util.Collections;
     27 import java.util.HashMap;
     28 import java.util.List;
     29 import java.util.Map;
     30 
     31 /**
     32  * Robolectric implementation of {@link android.os.UserManager}.
     33  */
     34 @Implements(value = UserManager.class, minSdk = JELLY_BEAN_MR1)
     35 public class ShadowUserManager {
     36 
     37   private boolean userUnlocked = true;
     38   private boolean managedProfile = false;
     39   private boolean isDemoUser = false;
     40   private boolean isAdminUser = false;
     41   private Map<UserHandle, Bundle> userRestrictions = new HashMap<>();
     42   private BiMap<UserHandle, Long> userProfiles = HashBiMap.create();
     43   private Map<String, Bundle> applicationRestrictions = new HashMap<>();
     44   private int nextUserSerial = 0;
     45   private Map<UserHandle, UserState> userState = new HashMap<>();
     46   private Context context;
     47   private boolean enforcePermissions;
     48 
     49   @Implementation
     50   public void __constructor__(Context context, IUserManager service) {
     51     this.context = context;
     52   }
     53 
     54   public ShadowUserManager() {
     55     addUserProfile(Process.myUserHandle());
     56   }
     57 
     58   public void enforcePermissionChecks(boolean enforcePermissions) {
     59     this.enforcePermissions = enforcePermissions;
     60   }
     61 
     62   /**
     63    * Compared to real Android, there is no check that the package name matches the application
     64    * package name and the method returns instantly.
     65    */
     66   @Implementation(minSdk = JELLY_BEAN_MR2)
     67   public Bundle getApplicationRestrictions(String packageName) {
     68     Bundle bundle = applicationRestrictions.get(packageName);
     69     return bundle != null ? bundle : new Bundle();
     70   }
     71 
     72   /**
     73    * Setter for {@link #getApplicationRestrictions(String)}
     74    */
     75   public void setApplicationRestrictions(String packageName, Bundle restrictions) {
     76     applicationRestrictions.put(packageName, restrictions);
     77   }
     78 
     79   /**
     80    * Adds a profile associated for the user that the calling process is running on.
     81    */
     82   public void addUserProfile(UserHandle userHandle) {
     83     setSerialNumberForUser(userHandle, nextUserSerial++);
     84   }
     85 
     86   @Implementation(minSdk = LOLLIPOP)
     87   public List<UserHandle> getUserProfiles(){
     88     return ImmutableList.copyOf(userProfiles.keySet());
     89   }
     90 
     91   @Implementation(minSdk = LOLLIPOP)
     92   protected List<UserInfo> getProfiles(int userHandle) {
     93     return Collections.emptyList();
     94   }
     95 
     96   @Implementation(minSdk = LOLLIPOP)
     97   protected UserInfo getProfileParent(int userHandle) {
     98     return null;
     99   }
    100 
    101   @Implementation(minSdk = N)
    102   public boolean isUserUnlocked() {
    103     return userUnlocked;
    104   }
    105 
    106   /**
    107    * Setter for {@link UserManager#isUserUnlocked()}
    108    */
    109   public void setUserUnlocked(boolean userUnlocked) {
    110     this.userUnlocked = userUnlocked;
    111   }
    112 
    113   @Implementation(minSdk = LOLLIPOP)
    114   public boolean isManagedProfile() {
    115     if (enforcePermissions && !hasManageUsersPermission()) {
    116       throw new SecurityException(
    117           "You need MANAGE_USERS permission to: check if specified user a " +
    118               "managed profile outside your profile group");
    119     }
    120     return managedProfile;
    121   }
    122 
    123   /**
    124    * Setter for {@link UserManager#isManagedProfile()}
    125    */
    126   public void setManagedProfile(boolean managedProfile) {
    127     this.managedProfile = managedProfile;
    128   }
    129 
    130   @Implementation(minSdk = LOLLIPOP)
    131   public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
    132     Bundle bundle = userRestrictions.get(userHandle);
    133     return bundle != null && bundle.getBoolean(restrictionKey);
    134   }
    135 
    136   public void setUserRestriction(UserHandle userHandle, String restrictionKey, boolean value) {
    137     Bundle bundle = getUserRestrictionsForUser(userHandle);
    138     bundle.putBoolean(restrictionKey, value);
    139   }
    140 
    141   /**
    142    * Removes all user restrictions set of a user identified by {@code userHandle}.
    143    */
    144   public void clearUserRestrictions(UserHandle userHandle) {
    145     if (userRestrictions.containsKey(userHandle)) {
    146       userRestrictions.remove(userHandle);
    147     }
    148   }
    149 
    150   @Implementation(minSdk = JELLY_BEAN_MR2)
    151   public Bundle getUserRestrictions(UserHandle userHandle) {
    152     return getUserRestrictionsForUser(userHandle);
    153   }
    154 
    155   private Bundle getUserRestrictionsForUser(UserHandle userHandle) {
    156     Bundle bundle = userRestrictions.get(userHandle);
    157     if (bundle == null) {
    158       bundle = new Bundle();
    159       userRestrictions.put(userHandle, bundle);
    160     }
    161     return bundle;
    162   }
    163 
    164   @Implementation
    165   public long getSerialNumberForUser(UserHandle userHandle) {
    166     Long result = userProfiles.get(userHandle);
    167     return result == null ? -1L : result;
    168   }
    169 
    170   /**
    171    * @deprecated prefer {@link #addUserProfile()} to ensure consistency of profiles known to
    172    * UserManager. Furthermore, calling this method for the current user, i.e:
    173    * {@link Process.myUserHandle()} is no longer necessary as this user is always known to
    174    * UserManager and has a preassigned serial number.
    175    */
    176   @Deprecated
    177   public void setSerialNumberForUser(UserHandle userHandle, long serialNumber) {
    178     userProfiles.put(userHandle, serialNumber);
    179   }
    180 
    181   @Implementation
    182   public UserHandle getUserForSerialNumber(long serialNumber) {
    183     return userProfiles.inverse().get(serialNumber);
    184   }
    185 
    186   private boolean hasManageUsersPermission() {
    187     return context.getPackageManager().checkPermission(permission.MANAGE_USERS, context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
    188   }
    189 
    190   private void checkPermissions() {
    191     // TODO Ensure permisions
    192     //              throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS
    193     // permission "
    194     //                + "to: check " + name);throw new SecurityException();
    195   }
    196 
    197   @Implementation(minSdk = N_MR1)
    198   public boolean isDemoUser() {
    199     return isDemoUser;
    200   }
    201 
    202   /**
    203    * Sets that the current user is a demo user; controls the return value of
    204    * {@link UserManager#isDemoUser}.
    205    */
    206   public void setIsDemoUser(boolean isDemoUser) {
    207     this.isDemoUser = isDemoUser;
    208   }
    209 
    210   @Implementation(minSdk = N_MR1)
    211   public boolean isAdminUser() {
    212     return isAdminUser;
    213   }
    214 
    215   /**
    216    * Sets that the current user is an admin user; controls the return value of
    217    * {@link UserManager#isAdminUser}.
    218    */
    219   public void setIsAdminUser(boolean isAdminUser) {
    220     this.isAdminUser = isAdminUser;
    221   }
    222 
    223   @Implementation
    224   public boolean isUserRunning(UserHandle handle) {
    225     checkPermissions();
    226     UserState state = userState.get(handle);
    227 
    228     if (state == UserState.STATE_RUNNING_LOCKED
    229         || state == UserState.STATE_RUNNING_UNLOCKED
    230         || state == UserState.STATE_RUNNING_UNLOCKING) {
    231       return true;
    232     } else {
    233       return false;
    234     }
    235   }
    236 
    237   @Implementation
    238   public boolean isUserRunningOrStopping(UserHandle handle) {
    239     checkPermissions();
    240     UserState state = userState.get(handle);
    241 
    242     if (state == UserState.STATE_RUNNING_LOCKED
    243         || state == UserState.STATE_RUNNING_UNLOCKED
    244         || state == UserState.STATE_RUNNING_UNLOCKING
    245         || state == UserState.STATE_STOPPING) {
    246       return true;
    247     } else {
    248       return false;
    249     }
    250   }
    251 
    252   /**
    253    * Describes the current state of the user. State can be set using
    254    *  {@link UserManager#setUserState()}
    255    */
    256   public enum UserState {
    257     // User is first coming up.
    258     STATE_BOOTING,
    259     // User is in the locked state.
    260     STATE_RUNNING_LOCKED,
    261     // User is in the unlocking state.
    262     STATE_RUNNING_UNLOCKING,
    263     // User is in the running state.
    264     STATE_RUNNING_UNLOCKED,
    265     // User is in the initial process of being stopped.
    266     STATE_STOPPING,
    267     // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
    268     STATE_SHUTDOWN
    269   }
    270 
    271   /**
    272    * Sets the current state for a given user, see {@link #isUserRunning()}
    273    * and {@link #isUserRunningOrStopping()}
    274    */
    275   public void setUserState(UserHandle handle, UserState state) {
    276     userState.put(handle, state);
    277   }
    278 
    279   @Implementation
    280   public List<UserInfo> getUsers() {
    281     // Implement this - return empty list to avoid NPE from call to getUserCount()
    282     return ImmutableList.of();
    283   }
    284 }
    285