1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.testutils.shadow; 18 19 import android.annotation.UserIdInt; 20 import android.content.pm.UserInfo; 21 import android.os.Bundle; 22 import android.os.UserHandle; 23 import android.os.UserManager; 24 import android.os.UserManager.EnforcingUser; 25 26 import com.google.android.collect.Maps; 27 28 import org.robolectric.RuntimeEnvironment; 29 import org.robolectric.annotation.Implementation; 30 import org.robolectric.annotation.Implements; 31 import org.robolectric.annotation.Resetter; 32 import org.robolectric.shadow.api.Shadow; 33 34 import java.util.ArrayList; 35 import java.util.Collections; 36 import java.util.HashMap; 37 import java.util.HashSet; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Set; 41 42 @Implements(value = UserManager.class) 43 public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager { 44 45 private static boolean sIsSupportsMultipleUsers; 46 47 private static final int PRIMARY_USER_ID = 0; 48 49 private final List<String> mBaseRestrictions = new ArrayList<>(); 50 private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>(); 51 private final List<UserInfo> mUserProfileInfos = new ArrayList<>(); 52 private final Set<Integer> mManagedProfiles = new HashSet<>(); 53 private final Set<String> mEnabledTypes = new HashSet<>(); 54 private boolean mIsQuietModeEnabled = false; 55 private int[] profileIdsForUser = new int[0]; 56 private boolean mUserSwitchEnabled; 57 private Bundle mDefaultGuestUserRestriction = new Bundle(); 58 private boolean mIsGuestUser = false; 59 60 private @UserManager.UserSwitchabilityResult int mSwitchabilityStatus = 61 UserManager.SWITCHABILITY_STATUS_OK; 62 private final Map<Integer, Integer> mSameProfileGroupIds = Maps.newHashMap(); 63 addProfile(UserInfo userInfo)64 public void addProfile(UserInfo userInfo) { 65 mUserProfileInfos.add(userInfo); 66 } 67 68 @Resetter reset()69 public static void reset() { 70 sIsSupportsMultipleUsers = false; 71 } 72 73 @Implementation getProfiles(@serIdInt int userHandle)74 protected List<UserInfo> getProfiles(@UserIdInt int userHandle) { 75 return mUserProfileInfos; 76 } 77 78 @Implementation getProfileIds(@serIdInt int userHandle, boolean enabledOnly)79 protected int[] getProfileIds(@UserIdInt int userHandle, boolean enabledOnly) { 80 int[] ids = new int[mUserProfileInfos.size()]; 81 for (int i = 0; i < mUserProfileInfos.size(); i++) { 82 ids[i] = mUserProfileInfos.get(i).id; 83 } 84 return ids; 85 } 86 87 @Implementation getCredentialOwnerProfile(@serIdInt int userHandle)88 protected int getCredentialOwnerProfile(@UserIdInt int userHandle) { 89 return userHandle; 90 } 91 92 @Implementation hasBaseUserRestriction(String restrictionKey, UserHandle userHandle)93 protected boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) { 94 return mBaseRestrictions.contains(restrictionKey); 95 } 96 addBaseUserRestriction(String restriction)97 public void addBaseUserRestriction(String restriction) { 98 mBaseRestrictions.add(restriction); 99 } 100 101 @Implementation getDefaultGuestRestrictions()102 protected Bundle getDefaultGuestRestrictions() { 103 return mDefaultGuestUserRestriction; 104 } 105 106 @Implementation setDefaultGuestRestrictions(Bundle restrictions)107 protected void setDefaultGuestRestrictions(Bundle restrictions) { 108 mDefaultGuestUserRestriction = restrictions; 109 } 110 addGuestUserRestriction(String restriction)111 public void addGuestUserRestriction(String restriction) { 112 mDefaultGuestUserRestriction.putBoolean(restriction, true); 113 } 114 hasGuestUserRestriction(String restriction, boolean expectedValue)115 public boolean hasGuestUserRestriction(String restriction, boolean expectedValue) { 116 return mDefaultGuestUserRestriction.containsKey(restriction) 117 && mDefaultGuestUserRestriction.getBoolean(restriction) == expectedValue; 118 } 119 120 121 @Implementation hasUserRestriction(String restrictionKey)122 protected boolean hasUserRestriction(String restrictionKey) { 123 return hasUserRestriction(restrictionKey, UserHandle.of(UserHandle.myUserId())); 124 } 125 getShadow()126 public static ShadowUserManager getShadow() { 127 return (ShadowUserManager) Shadow.extract( 128 RuntimeEnvironment.application.getSystemService(UserManager.class)); 129 } 130 131 @Implementation getUserRestrictionSources( String restrictionKey, UserHandle userHandle)132 protected List<EnforcingUser> getUserRestrictionSources( 133 String restrictionKey, UserHandle userHandle) { 134 // Return empty list when there is no enforcing user, otherwise might trigger 135 // NullPointer Exception in RestrictedLockUtils.checkIfRestrictionEnforced. 136 List<EnforcingUser> enforcingUsers = 137 mRestrictionSources.get(restrictionKey + userHandle.getIdentifier()); 138 return enforcingUsers == null ? Collections.emptyList() : enforcingUsers; 139 } 140 setUserRestrictionSources( String restrictionKey, UserHandle userHandle, List<EnforcingUser> enforcers)141 public void setUserRestrictionSources( 142 String restrictionKey, UserHandle userHandle, List<EnforcingUser> enforcers) { 143 mRestrictionSources.put(restrictionKey + userHandle.getIdentifier(), enforcers); 144 } 145 146 @Implementation isQuietModeEnabled(UserHandle userHandle)147 protected boolean isQuietModeEnabled(UserHandle userHandle) { 148 return mIsQuietModeEnabled; 149 } 150 setQuietModeEnabled(boolean enabled)151 public void setQuietModeEnabled(boolean enabled) { 152 mIsQuietModeEnabled = enabled; 153 } 154 155 @Implementation getProfileIdsWithDisabled(@serIdInt int userId)156 protected int[] getProfileIdsWithDisabled(@UserIdInt int userId) { 157 return profileIdsForUser; 158 } 159 setProfileIdsWithDisabled(int[] profileIds)160 public void setProfileIdsWithDisabled(int[] profileIds) { 161 profileIdsForUser = profileIds; 162 } 163 164 @Implementation isUserSwitcherEnabled()165 protected boolean isUserSwitcherEnabled() { 166 return mUserSwitchEnabled; 167 } 168 169 @Implementation isManagedProfile(int userId)170 protected boolean isManagedProfile(int userId) { 171 return mManagedProfiles.contains(userId); 172 } 173 setManagedProfiles(Set<Integer> profileIds)174 public void setManagedProfiles(Set<Integer> profileIds) { 175 mManagedProfiles.clear(); 176 mManagedProfiles.addAll(profileIds); 177 } 178 setUserSwitcherEnabled(boolean userSwitchEnabled)179 public void setUserSwitcherEnabled(boolean userSwitchEnabled) { 180 mUserSwitchEnabled = userSwitchEnabled; 181 } 182 183 @Implementation supportsMultipleUsers()184 protected static boolean supportsMultipleUsers() { 185 return sIsSupportsMultipleUsers; 186 } 187 188 @Implementation isSameProfileGroup(@serIdInt int userId, int otherUserId)189 protected boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) { 190 return mSameProfileGroupIds.containsKey(userId) 191 && mSameProfileGroupIds.get(userId) == otherUserId 192 || mSameProfileGroupIds.containsKey(otherUserId) 193 && mSameProfileGroupIds.get(otherUserId) == userId; 194 } 195 getSameProfileGroupIds()196 public Map<Integer, Integer> getSameProfileGroupIds() { 197 return mSameProfileGroupIds; 198 } 199 setSupportsMultipleUsers(boolean supports)200 public void setSupportsMultipleUsers(boolean supports) { 201 sIsSupportsMultipleUsers = supports; 202 } 203 204 @Implementation getUserInfo(@serIdInt int userId)205 protected UserInfo getUserInfo(@UserIdInt int userId) { 206 return mUserProfileInfos.stream() 207 .filter(userInfo -> userInfo.id == userId) 208 .findFirst() 209 .orElse(super.getUserInfo(userId)); 210 } 211 212 @Implementation getUserSwitchability()213 protected @UserManager.UserSwitchabilityResult int getUserSwitchability() { 214 return mSwitchabilityStatus; 215 } 216 setSwitchabilityStatus(@serManager.UserSwitchabilityResult int newStatus)217 public void setSwitchabilityStatus(@UserManager.UserSwitchabilityResult int newStatus) { 218 mSwitchabilityStatus = newStatus; 219 } 220 221 @Implementation isUserTypeEnabled(String userType)222 protected boolean isUserTypeEnabled(String userType) { 223 return mEnabledTypes.contains(userType); 224 } 225 setUserTypeEnabled(String type, boolean enabled)226 public void setUserTypeEnabled(String type, boolean enabled) { 227 if (enabled) { 228 mEnabledTypes.add(type); 229 } else { 230 mEnabledTypes.remove(type); 231 } 232 } 233 234 @Implementation getPrimaryUser()235 protected UserInfo getPrimaryUser() { 236 return new UserInfo(PRIMARY_USER_ID, null, null, 237 UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); 238 } 239 setUserEphemeral(@serIdInt int userId, boolean enableEphemeral)240 protected boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) { 241 UserInfo userInfo = mUserProfileInfos.stream() 242 .filter(user -> user.id == userId) 243 .findFirst() 244 .orElse(super.getUserInfo(userId)); 245 246 boolean isSuccess = false; 247 boolean isEphemeralUser = 248 (userInfo.flags & UserInfo.FLAG_EPHEMERAL) != 0; 249 boolean isEphemeralOnCreateUser = 250 (userInfo.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) 251 != 0; 252 // when user is created in ephemeral mode via FLAG_EPHEMERAL 253 // its state cannot be changed. 254 // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state 255 if (!isEphemeralOnCreateUser) { 256 isSuccess = true; 257 if (isEphemeralUser != enableEphemeral) { 258 if (enableEphemeral) { 259 userInfo.flags |= UserInfo.FLAG_EPHEMERAL; 260 } else { 261 userInfo.flags &= ~UserInfo.FLAG_EPHEMERAL; 262 } 263 } 264 } 265 return isSuccess; 266 } 267 268 @Implementation setUserAdmin(@serIdInt int userId)269 protected void setUserAdmin(@UserIdInt int userId) { 270 for (int i = 0; i < mUserProfileInfos.size(); i++) { 271 mUserProfileInfos.get(i).flags |= UserInfo.FLAG_ADMIN; 272 } 273 } 274 275 @Implementation isGuestUser()276 protected boolean isGuestUser() { 277 return mIsGuestUser; 278 } 279 setGuestUser(boolean isGuestUser)280 public void setGuestUser(boolean isGuestUser) { 281 mIsGuestUser = isGuestUser; 282 } 283 } 284