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 List<String> mGuestRestrictions = new ArrayList<>(); 51 private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>(); 52 private final List<UserInfo> mUserProfileInfos = new ArrayList<>(); 53 private final Set<Integer> mManagedProfiles = new HashSet<>(); 54 private final Set<String> mEnabledTypes = new HashSet<>(); 55 private boolean mIsQuietModeEnabled = false; 56 private int[] profileIdsForUser = new int[0]; 57 private boolean mUserSwitchEnabled; 58 59 private @UserManager.UserSwitchabilityResult int mSwitchabilityStatus = 60 UserManager.SWITCHABILITY_STATUS_OK; 61 private final Map<Integer, Integer> mSameProfileGroupIds = Maps.newHashMap(); 62 addProfile(UserInfo userInfo)63 public void addProfile(UserInfo userInfo) { 64 mUserProfileInfos.add(userInfo); 65 } 66 67 @Resetter reset()68 public static void reset() { 69 sIsSupportsMultipleUsers = false; 70 } 71 72 @Implementation getProfiles(@serIdInt int userHandle)73 protected List<UserInfo> getProfiles(@UserIdInt int userHandle) { 74 return mUserProfileInfos; 75 } 76 77 @Implementation getProfileIds(@serIdInt int userHandle, boolean enabledOnly)78 protected int[] getProfileIds(@UserIdInt int userHandle, boolean enabledOnly) { 79 int[] ids = new int[mUserProfileInfos.size()]; 80 for (int i = 0; i < mUserProfileInfos.size(); i++) { 81 ids[i] = mUserProfileInfos.get(i).id; 82 } 83 return ids; 84 } 85 86 @Implementation getCredentialOwnerProfile(@serIdInt int userHandle)87 protected int getCredentialOwnerProfile(@UserIdInt int userHandle) { 88 return userHandle; 89 } 90 91 @Implementation hasBaseUserRestriction(String restrictionKey, UserHandle userHandle)92 protected boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) { 93 return mBaseRestrictions.contains(restrictionKey); 94 } 95 addBaseUserRestriction(String restriction)96 public void addBaseUserRestriction(String restriction) { 97 mBaseRestrictions.add(restriction); 98 } 99 100 @Implementation getDefaultGuestRestrictions()101 protected Bundle getDefaultGuestRestrictions() { 102 Bundle bundle = new Bundle(); 103 mGuestRestrictions.forEach(restriction -> bundle.putBoolean(restriction, true)); 104 return bundle; 105 } 106 addGuestUserRestriction(String restriction)107 public void addGuestUserRestriction(String restriction) { 108 mGuestRestrictions.add(restriction); 109 } 110 111 @Implementation hasUserRestriction(String restrictionKey)112 protected boolean hasUserRestriction(String restrictionKey) { 113 return hasUserRestriction(restrictionKey, UserHandle.of(UserHandle.myUserId())); 114 } 115 getShadow()116 public static ShadowUserManager getShadow() { 117 return (ShadowUserManager) Shadow.extract( 118 RuntimeEnvironment.application.getSystemService(UserManager.class)); 119 } 120 121 @Implementation getUserRestrictionSources( String restrictionKey, UserHandle userHandle)122 protected List<EnforcingUser> getUserRestrictionSources( 123 String restrictionKey, UserHandle userHandle) { 124 // Return empty list when there is no enforcing user, otherwise might trigger 125 // NullPointer Exception in RestrictedLockUtils.checkIfRestrictionEnforced. 126 List<EnforcingUser> enforcingUsers = 127 mRestrictionSources.get(restrictionKey + userHandle.getIdentifier()); 128 return enforcingUsers == null ? Collections.emptyList() : enforcingUsers; 129 } 130 setUserRestrictionSources( String restrictionKey, UserHandle userHandle, List<EnforcingUser> enforcers)131 public void setUserRestrictionSources( 132 String restrictionKey, UserHandle userHandle, List<EnforcingUser> enforcers) { 133 mRestrictionSources.put(restrictionKey + userHandle.getIdentifier(), enforcers); 134 } 135 136 @Implementation isQuietModeEnabled(UserHandle userHandle)137 protected boolean isQuietModeEnabled(UserHandle userHandle) { 138 return mIsQuietModeEnabled; 139 } 140 setQuietModeEnabled(boolean enabled)141 public void setQuietModeEnabled(boolean enabled) { 142 mIsQuietModeEnabled = enabled; 143 } 144 145 @Implementation getProfileIdsWithDisabled(@serIdInt int userId)146 protected int[] getProfileIdsWithDisabled(@UserIdInt int userId) { 147 return profileIdsForUser; 148 } 149 setProfileIdsWithDisabled(int[] profileIds)150 public void setProfileIdsWithDisabled(int[] profileIds) { 151 profileIdsForUser = profileIds; 152 } 153 154 @Implementation isUserSwitcherEnabled()155 protected boolean isUserSwitcherEnabled() { 156 return mUserSwitchEnabled; 157 } 158 159 @Implementation isManagedProfile(int userId)160 protected boolean isManagedProfile(int userId) { 161 return mManagedProfiles.contains(userId); 162 } 163 setManagedProfiles(Set<Integer> profileIds)164 public void setManagedProfiles(Set<Integer> profileIds) { 165 mManagedProfiles.clear(); 166 mManagedProfiles.addAll(profileIds); 167 } 168 setUserSwitcherEnabled(boolean userSwitchEnabled)169 public void setUserSwitcherEnabled(boolean userSwitchEnabled) { 170 mUserSwitchEnabled = userSwitchEnabled; 171 } 172 173 @Implementation supportsMultipleUsers()174 protected static boolean supportsMultipleUsers() { 175 return sIsSupportsMultipleUsers; 176 } 177 178 @Implementation isSameProfileGroup(@serIdInt int userId, int otherUserId)179 protected boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) { 180 return mSameProfileGroupIds.containsKey(userId) 181 && mSameProfileGroupIds.get(userId) == otherUserId 182 || mSameProfileGroupIds.containsKey(otherUserId) 183 && mSameProfileGroupIds.get(otherUserId) == userId; 184 } 185 getSameProfileGroupIds()186 public Map<Integer, Integer> getSameProfileGroupIds() { 187 return mSameProfileGroupIds; 188 } 189 setSupportsMultipleUsers(boolean supports)190 public void setSupportsMultipleUsers(boolean supports) { 191 sIsSupportsMultipleUsers = supports; 192 } 193 194 @Implementation getUserInfo(@serIdInt int userId)195 protected UserInfo getUserInfo(@UserIdInt int userId) { 196 return mUserProfileInfos.stream() 197 .filter(userInfo -> userInfo.id == userId) 198 .findFirst() 199 .orElse(super.getUserInfo(userId)); 200 } 201 202 @Implementation getUserSwitchability()203 protected @UserManager.UserSwitchabilityResult int getUserSwitchability() { 204 return mSwitchabilityStatus; 205 } 206 setSwitchabilityStatus(@serManager.UserSwitchabilityResult int newStatus)207 public void setSwitchabilityStatus(@UserManager.UserSwitchabilityResult int newStatus) { 208 mSwitchabilityStatus = newStatus; 209 } 210 211 @Implementation isUserTypeEnabled(String userType)212 protected boolean isUserTypeEnabled(String userType) { 213 return mEnabledTypes.contains(userType); 214 } 215 setUserTypeEnabled(String type, boolean enabled)216 public void setUserTypeEnabled(String type, boolean enabled) { 217 if (enabled) { 218 mEnabledTypes.add(type); 219 } else { 220 mEnabledTypes.remove(type); 221 } 222 } 223 224 @Implementation getPrimaryUser()225 protected UserInfo getPrimaryUser() { 226 return new UserInfo(PRIMARY_USER_ID, null, null, 227 UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); 228 } 229 setUserEphemeral(@serIdInt int userId, boolean enableEphemeral)230 protected boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) { 231 UserInfo userInfo = mUserProfileInfos.stream() 232 .filter(user -> user.id == userId) 233 .findFirst() 234 .orElse(super.getUserInfo(userId)); 235 236 boolean isSuccess = false; 237 boolean isEphemeralUser = 238 (userInfo.flags & UserInfo.FLAG_EPHEMERAL) != 0; 239 boolean isEphemeralOnCreateUser = 240 (userInfo.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) 241 != 0; 242 // when user is created in ephemeral mode via FLAG_EPHEMERAL 243 // its state cannot be changed. 244 // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state 245 if (!isEphemeralOnCreateUser) { 246 isSuccess = true; 247 if (isEphemeralUser != enableEphemeral) { 248 if (enableEphemeral) { 249 userInfo.flags |= UserInfo.FLAG_EPHEMERAL; 250 } else { 251 userInfo.flags &= ~UserInfo.FLAG_EPHEMERAL; 252 } 253 } 254 } 255 return isSuccess; 256 } 257 } 258