| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.car.userlib; |
| |
| import android.Manifest; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SystemApi; |
| import android.app.ActivityManager; |
| import android.content.Context; |
| import android.content.pm.UserInfo; |
| import android.graphics.Bitmap; |
| import android.os.Bundle; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.provider.Settings; |
| import android.sysprop.CarProperties; |
| import android.telephony.TelephonyManager; |
| import android.text.TextUtils; |
| import android.util.Log; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.os.RoSystemProperties; |
| import com.android.internal.util.UserIcons; |
| |
| import com.google.android.collect.Sets; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * Helper class for {@link UserManager}, this is meant to be used by builds that support |
| * Multi-user model with headless user 0. User 0 is not associated with a real person, and |
| * can not be brought to foreground. |
| * |
| * <p>This class provides method for user management, including creating, removing, adding |
| * and switching users. Methods related to get users will exclude system user by default. |
| * |
| * @hide |
| */ |
| public final class CarUserManagerHelper { |
| private static final String TAG = "CarUserManagerHelper"; |
| |
| private static final int BOOT_USER_NOT_FOUND = -1; |
| |
| /** |
| * Default set of restrictions for Non-Admin users. |
| */ |
| private static final Set<String> DEFAULT_NON_ADMIN_RESTRICTIONS = Sets.newArraySet( |
| UserManager.DISALLOW_FACTORY_RESET |
| ); |
| |
| /** |
| * Additional optional set of restrictions for Non-Admin users. These are the restrictions |
| * configurable via Settings. |
| */ |
| public static final Set<String> OPTIONAL_NON_ADMIN_RESTRICTIONS = Sets.newArraySet( |
| UserManager.DISALLOW_ADD_USER, |
| UserManager.DISALLOW_OUTGOING_CALLS, |
| UserManager.DISALLOW_SMS, |
| UserManager.DISALLOW_INSTALL_APPS, |
| UserManager.DISALLOW_UNINSTALL_APPS |
| ); |
| |
| /** |
| * Default set of restrictions for Guest users. |
| */ |
| private static final Set<String> DEFAULT_GUEST_RESTRICTIONS = Sets.newArraySet( |
| UserManager.DISALLOW_FACTORY_RESET, |
| UserManager.DISALLOW_REMOVE_USER, |
| UserManager.DISALLOW_MODIFY_ACCOUNTS, |
| UserManager.DISALLOW_INSTALL_APPS, |
| UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, |
| UserManager.DISALLOW_UNINSTALL_APPS |
| ); |
| |
| private final Context mContext; |
| private final UserManager mUserManager; |
| private final ActivityManager mActivityManager; |
| private final TestableFrameworkWrapper mTestableFrameworkWrapper; |
| private String mDefaultAdminName; |
| private Bitmap mDefaultGuestUserIcon; |
| |
| /** |
| * Initializes with a default name for admin users. |
| * |
| * @param context Application Context |
| */ |
| public CarUserManagerHelper(Context context) { |
| this(context, new TestableFrameworkWrapper()); |
| } |
| |
| @VisibleForTesting |
| CarUserManagerHelper(Context context, TestableFrameworkWrapper testableFrameworkWrapper) { |
| mContext = context.getApplicationContext(); |
| mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); |
| mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); |
| mTestableFrameworkWrapper = testableFrameworkWrapper; |
| } |
| |
| /** |
| * Set last active user. |
| * |
| * @param userId last active user id. |
| */ |
| public void setLastActiveUser(int userId) { |
| Settings.Global.putInt( |
| mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID, userId); |
| } |
| |
| /** |
| * Get user id for the last active user. |
| * |
| * @return user id of the last active user. |
| */ |
| public int getLastActiveUser() { |
| return Settings.Global.getInt( |
| mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID, |
| /* default user id= */ UserHandle.USER_SYSTEM); |
| } |
| |
| /** |
| * Gets the user id for the initial user to boot into. This is only applicable for headless |
| * system user model. This method checks for a system property and will only work for system |
| * apps. |
| * |
| * This method checks for the initial user via three mechanisms in this order: |
| * <ol> |
| * <li>Check for a boot user override via {@link CarProperties#boot_user_override_id()}</li> |
| * <li>Check for the last active user in the system</li> |
| * <li>Fallback to the smallest user id that is not {@link UserHandle.USER_SYSTEM}</li> |
| * </ol> |
| * |
| * If any step fails to retrieve the stored id or the retrieved id does not exist on device, |
| * then it will move onto the next step. |
| * |
| * @return user id of the initial user to boot into on the device. |
| */ |
| @SystemApi |
| public int getInitialUser() { |
| List<Integer> allUsers = userInfoListToUserIdList(getAllPersistentUsers()); |
| |
| int bootUserOverride = mTestableFrameworkWrapper.getBootUserOverrideId(BOOT_USER_NOT_FOUND); |
| |
| // If an override user is present and a real user, return it |
| if (bootUserOverride != BOOT_USER_NOT_FOUND |
| && allUsers.contains(bootUserOverride)) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Boot user id override found for initial user, user id: " |
| + bootUserOverride); |
| } |
| return bootUserOverride; |
| } |
| |
| // If the last active user is not the SYSTEM user and is a real user, return it |
| int lastActiveUser = getLastActiveUser(); |
| if (lastActiveUser != UserHandle.USER_SYSTEM |
| && allUsers.contains(lastActiveUser)) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Last active user loaded for initial user, user id: " |
| + lastActiveUser); |
| } |
| return lastActiveUser; |
| } |
| |
| // If all else fails, return the smallest user id |
| int returnId = Collections.min(allUsers); |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Saved ids were invalid. Returning smallest user id, user id: " |
| + returnId); |
| } |
| return returnId; |
| } |
| |
| private List<Integer> userInfoListToUserIdList(List<UserInfo> allUsers) { |
| ArrayList<Integer> list = new ArrayList<>(allUsers.size()); |
| for (UserInfo userInfo : allUsers) { |
| list.add(userInfo.id); |
| } |
| return list; |
| } |
| |
| /** |
| * Sets default guest restrictions that will be applied every time a Guest user is created. |
| * |
| * <p> Restrictions are written to disk and persistent across boots. |
| */ |
| public void initDefaultGuestRestrictions() { |
| Bundle defaultGuestRestrictions = new Bundle(); |
| for (String restriction : DEFAULT_GUEST_RESTRICTIONS) { |
| defaultGuestRestrictions.putBoolean(restriction, true); |
| } |
| mUserManager.setDefaultGuestRestrictions(defaultGuestRestrictions); |
| } |
| |
| /** |
| * Returns {@code true} if the system is in the headless user 0 model. |
| * |
| * @return {@boolean true} if headless system user. |
| */ |
| public boolean isHeadlessSystemUser() { |
| return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; |
| } |
| |
| /** |
| * Gets UserInfo for the current foreground user. |
| * |
| * Concept of foreground user is relevant for the multi-user deployment. Foreground user |
| * corresponds to the currently "logged in" user. |
| * |
| * @return {@link UserInfo} for the foreground user. |
| */ |
| public UserInfo getCurrentForegroundUserInfo() { |
| return mUserManager.getUserInfo(getCurrentForegroundUserId()); |
| } |
| |
| /** |
| * @return Id of the current foreground user. |
| */ |
| public int getCurrentForegroundUserId() { |
| return mActivityManager.getCurrentUser(); |
| } |
| |
| /** |
| * Gets UserInfo for the user running the caller process. |
| * |
| * <p>Differentiation between foreground user and current process user is relevant for |
| * multi-user deployments. |
| * |
| * <p>Some multi-user aware components (like SystemUI) needs to run a singleton component |
| * in system user. Current process user is always the same for that component, even when |
| * the foreground user changes. |
| * |
| * @return {@link UserInfo} for the user running the current process. |
| */ |
| public UserInfo getCurrentProcessUserInfo() { |
| return mUserManager.getUserInfo(getCurrentProcessUserId()); |
| } |
| |
| /** |
| * @return Id for the user running the current process. |
| */ |
| public int getCurrentProcessUserId() { |
| return UserHandle.myUserId(); |
| } |
| |
| /** |
| * Gets all the existing users on the system that are not currently running as |
| * the foreground user. |
| * These are all the users that can be switched to from the foreground user. |
| * |
| * @return List of {@code UserInfo} for each user that is not the foreground user. |
| */ |
| public List<UserInfo> getAllSwitchableUsers() { |
| if (isHeadlessSystemUser()) { |
| return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId()); |
| } else { |
| return getAllUsersExceptSpecifiedUser(getCurrentForegroundUserId()); |
| } |
| } |
| |
| /** |
| * Gets all the users that can be brought to the foreground on the system. |
| * |
| * @return List of {@code UserInfo} for users that associated with a real person. |
| */ |
| public List<UserInfo> getAllUsers() { |
| if (isHeadlessSystemUser()) { |
| return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM); |
| } else { |
| return mUserManager.getUsers(/* excludeDying= */ true); |
| } |
| } |
| |
| /** |
| * Gets all the users that are non-ephemeral and can be brought to the foreground on the system. |
| * |
| * @return List of {@code UserInfo} for non-ephemeral users that associated with a real person. |
| */ |
| public List<UserInfo> getAllPersistentUsers() { |
| List<UserInfo> users = getAllUsers(); |
| for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { |
| UserInfo userInfo = iterator.next(); |
| if (userInfo.isEphemeral()) { |
| // Remove user that is ephemeral. |
| iterator.remove(); |
| } |
| } |
| return users; |
| } |
| |
| /** |
| * Gets all the users that can be brought to the foreground on the system that have admin roles. |
| * |
| * @return List of {@code UserInfo} for admin users that associated with a real person. |
| */ |
| public List<UserInfo> getAllAdminUsers() { |
| List<UserInfo> users = getAllUsers(); |
| |
| for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { |
| UserInfo userInfo = iterator.next(); |
| if (!userInfo.isAdmin()) { |
| // Remove user that is not admin. |
| iterator.remove(); |
| } |
| } |
| return users; |
| } |
| |
| /** |
| * Gets all users that are not guests. |
| * |
| * @return List of {@code UserInfo} for all users who are not guest users. |
| */ |
| public List<UserInfo> getAllUsersExceptGuests() { |
| List<UserInfo> users = getAllUsers(); |
| |
| for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { |
| UserInfo userInfo = iterator.next(); |
| if (userInfo.isGuest()) { |
| // Remove guests. |
| iterator.remove(); |
| } |
| } |
| return users; |
| } |
| |
| /** |
| * Get all the users except the one with userId passed in. |
| * |
| * @param userId of the user not to be returned. |
| * @return All users other than user with userId. |
| */ |
| private List<UserInfo> getAllUsersExceptSpecifiedUser(int userId) { |
| List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true); |
| |
| for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { |
| UserInfo userInfo = iterator.next(); |
| if (userInfo.id == userId) { |
| // Remove user with userId from the list. |
| iterator.remove(); |
| } |
| } |
| return users; |
| } |
| |
| /** |
| * Get all the users except system user and the one with userId passed in. |
| * |
| * @param userId of the user not to be returned. |
| * @return All users other than system user and user with userId. |
| */ |
| private List<UserInfo> getAllUsersExceptSystemUserAndSpecifiedUser(int userId) { |
| List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true); |
| |
| for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { |
| UserInfo userInfo = iterator.next(); |
| if (userInfo.id == userId || userInfo.id == UserHandle.USER_SYSTEM) { |
| // Remove user with userId from the list. |
| iterator.remove(); |
| } |
| } |
| return users; |
| } |
| |
| /** |
| * Maximum number of users allowed on the device. This includes real users, managed profiles |
| * and restricted users, but excludes guests. |
| * |
| * <p> It excludes system user in headless system user model. |
| * |
| * @return Maximum number of users that can be present on the device. |
| */ |
| private int getMaxSupportedUsers() { |
| if (isHeadlessSystemUser()) { |
| return mTestableFrameworkWrapper.userManagerGetMaxSupportedUsers() - 1; |
| } |
| return mTestableFrameworkWrapper.userManagerGetMaxSupportedUsers(); |
| } |
| |
| /** |
| * Get the maximum number of real (non-guest, non-managed profile) users that can be created on |
| * the device. This is a dynamic value and it decreases with the increase of the number of |
| * managed profiles on the device. |
| * |
| * <p> It excludes system user in headless system user model. |
| * |
| * @return Maximum number of real users that can be created. |
| */ |
| public int getMaxSupportedRealUsers() { |
| return getMaxSupportedUsers() - getManagedProfilesCount(); |
| } |
| |
| /** |
| * Returns true if the maximum number of users on the device has been reached, false otherwise. |
| */ |
| public boolean isUserLimitReached() { |
| int countNonGuestUsers = getAllUsersExceptGuests().size(); |
| int maxSupportedUsers = getMaxSupportedUsers(); |
| |
| if (countNonGuestUsers > maxSupportedUsers) { |
| Log.e(TAG, "There are more users on the device than allowed."); |
| return true; |
| } |
| |
| return getAllUsersExceptGuests().size() == maxSupportedUsers; |
| } |
| |
| private int getManagedProfilesCount() { |
| List<UserInfo> users = getAllUsers(); |
| |
| // Count all users that are managed profiles of another user. |
| int managedProfilesCount = 0; |
| for (UserInfo user : users) { |
| if (user.isManagedProfile()) { |
| managedProfilesCount++; |
| } |
| } |
| return managedProfilesCount; |
| } |
| |
| // User information accessors |
| |
| /** |
| * Checks whether passed in user is the user that's running the current process. |
| * |
| * @param userInfo User to check. |
| * @return {@code true} if user running the process, {@code false} otherwise. |
| */ |
| public boolean isCurrentProcessUser(UserInfo userInfo) { |
| return getCurrentProcessUserId() == userInfo.id; |
| } |
| |
| // Foreground user information accessors. |
| |
| /** |
| * Return whether the foreground user has a restriction. |
| * |
| * @param restriction Restriction to check. Should be a UserManager.* restriction. |
| * @return Whether that restriction exists for the foreground user. |
| */ |
| private boolean foregroundUserHasUserRestriction(String restriction) { |
| return mUserManager.hasUserRestriction( |
| restriction, UserHandle.of(getCurrentForegroundUserId())); |
| } |
| |
| /** |
| * Checks if the foreground user can add new users. |
| */ |
| public boolean canForegroundUserAddUsers() { |
| return !foregroundUserHasUserRestriction(UserManager.DISALLOW_ADD_USER); |
| } |
| |
| /** |
| * Returns whether the foreground user can switch to other users. |
| * |
| * <p>For instance switching users is not allowed if the current user is in a phone call, |
| * or {@link #{UserManager.DISALLOW_USER_SWITCH} is set. |
| */ |
| public boolean canForegroundUserSwitchUsers() { |
| boolean inIdleCallState = TelephonyManager.getDefault().getCallState() |
| == TelephonyManager.CALL_STATE_IDLE; |
| boolean disallowUserSwitching = |
| foregroundUserHasUserRestriction(UserManager.DISALLOW_USER_SWITCH); |
| return (inIdleCallState && !disallowUserSwitching); |
| } |
| |
| // Current process user restriction accessors |
| |
| /** |
| * Returns whether the current process user can switch to other users. |
| * |
| * <p>For instance switching users is not allowed if the user is in a phone call, |
| * or {@link #{UserManager.DISALLOW_USER_SWITCH} is set. |
| */ |
| private boolean canCurrentProcessSwitchUsers() { |
| boolean inIdleCallState = TelephonyManager.getDefault().getCallState() |
| == TelephonyManager.CALL_STATE_IDLE; |
| boolean disallowUserSwitching = |
| mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH); |
| return (inIdleCallState && !disallowUserSwitching); |
| } |
| |
| /** |
| * Grants admin permissions to the user. |
| * |
| * @param user User to be upgraded to Admin status. |
| */ |
| @RequiresPermission(allOf = { |
| Manifest.permission.INTERACT_ACROSS_USERS_FULL, |
| Manifest.permission.MANAGE_USERS |
| }) |
| public void grantAdminPermissions(UserInfo user) { |
| if (!mUserManager.isAdminUser()) { |
| Log.w(TAG, "Only admin users can assign admin permissions."); |
| return; |
| } |
| |
| mUserManager.setUserAdmin(user.id); |
| |
| // Remove restrictions imposed on non-admins. |
| setDefaultNonAdminRestrictions(user, /* enable= */ false); |
| setOptionalNonAdminRestrictions(user, /* enable= */ false); |
| } |
| |
| /** |
| * Creates a new user on the system, the created user would be granted admin role. |
| * Only admins can create other admins. |
| * |
| * @param userName Name to give to the newly created user. |
| * @return Newly created admin user, null if failed to create a user. |
| */ |
| @Nullable |
| private UserInfo createNewAdminUser(String userName) { |
| if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) { |
| // Only Admins or System user can create other privileged users. |
| Log.e(TAG, "Only admin users and system user can create other admins."); |
| return null; |
| } |
| |
| UserInfo user = mUserManager.createUser(userName, UserInfo.FLAG_ADMIN); |
| if (user == null) { |
| // Couldn't create user, most likely because there are too many. |
| Log.w(TAG, "can't create admin user."); |
| return null; |
| } |
| assignDefaultIcon(user); |
| |
| return user; |
| } |
| |
| /** |
| * Creates a new non-admin user on the system. |
| * |
| * @param userName Name to give to the newly created user. |
| * @return Newly created non-admin user, null if failed to create a user. |
| */ |
| @Nullable |
| public UserInfo createNewNonAdminUser(String userName) { |
| UserInfo user = mUserManager.createUser(userName, 0); |
| if (user == null) { |
| // Couldn't create user, most likely because there are too many. |
| Log.w(TAG, "can't create non-admin user."); |
| return null; |
| } |
| setDefaultNonAdminRestrictions(user, /* enable= */ true); |
| |
| // Each non-admin has sms and outgoing call restrictions applied by the UserManager on |
| // creation. We want to enable these permissions by default in the car. |
| mUserManager.setUserRestriction( |
| UserManager.DISALLOW_SMS, /* enable= */ false, user.getUserHandle()); |
| mUserManager.setUserRestriction( |
| UserManager.DISALLOW_OUTGOING_CALLS, /* enable= */ false, user.getUserHandle()); |
| |
| assignDefaultIcon(user); |
| return user; |
| } |
| |
| /** |
| * Sets the values of default Non-Admin restrictions to the passed in value. |
| * |
| * @param userInfo User to set restrictions on. |
| * @param enable If true, restriction is ON, If false, restriction is OFF. |
| */ |
| public void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) { |
| for (String restriction : DEFAULT_NON_ADMIN_RESTRICTIONS) { |
| mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle()); |
| } |
| } |
| |
| /** |
| * Sets the values of settings controllable restrictions to the passed in value. |
| * |
| * @param userInfo User to set restrictions on. |
| * @param enable If true, restriction is ON, If false, restriction is OFF. |
| */ |
| private void setOptionalNonAdminRestrictions(UserInfo userInfo, boolean enable) { |
| for (String restriction : OPTIONAL_NON_ADMIN_RESTRICTIONS) { |
| mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle()); |
| } |
| } |
| |
| /** |
| * Tries to remove the user that's passed in. System user cannot be removed. |
| * If the user to be removed is user currently running the process, |
| * it switches to the guest user first, and then removes the user. |
| * If the user being removed is the last admin user, this will create a new admin user. |
| * |
| * @param userInfo User to be removed |
| * @param guestUserName User name to use for the guest user if we need to switch to it |
| * @return {@code true} if user is successfully removed, {@code false} otherwise. |
| */ |
| public boolean removeUser(UserInfo userInfo, String guestUserName) { |
| if (userInfo.id == UserHandle.USER_SYSTEM) { |
| Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed."); |
| return false; |
| } |
| |
| // Try to create a new admin before deleting the current one. |
| if (userInfo.isAdmin() && getAllAdminUsers().size() <= 1) { |
| return removeLastAdmin(userInfo); |
| } |
| |
| if (!mUserManager.isAdminUser() && !isCurrentProcessUser(userInfo)) { |
| // If the caller is non-admin, they can only delete themselves. |
| Log.e(TAG, "Non-admins cannot remove other users."); |
| return false; |
| } |
| |
| if (userInfo.id == getCurrentForegroundUserId()) { |
| if (!canCurrentProcessSwitchUsers()) { |
| // If we can't switch to a different user, we can't exit this one and therefore |
| // can't delete it. |
| Log.w(TAG, "User switching is not allowed. Current user cannot be deleted"); |
| return false; |
| } |
| startGuestSession(guestUserName); |
| } |
| |
| return mUserManager.removeUser(userInfo.id); |
| } |
| |
| private boolean removeLastAdmin(UserInfo userInfo) { |
| if (Log.isLoggable(TAG, Log.INFO)) { |
| Log.i(TAG, "User " + userInfo.id |
| + " is the last admin user on device. Creating a new admin."); |
| } |
| |
| UserInfo newAdmin = createNewAdminUser(getDefaultAdminName()); |
| if (newAdmin == null) { |
| Log.w(TAG, "Couldn't create another admin, cannot delete current user."); |
| return false; |
| } |
| |
| switchToUser(newAdmin); |
| return mUserManager.removeUser(userInfo.id); |
| } |
| |
| /** |
| * Switches (logs in) to another user given user id. |
| * |
| * @param id User id to switch to. |
| * @return {@code true} if user switching succeed. |
| */ |
| public boolean switchToUserId(int id) { |
| if (id == UserHandle.USER_SYSTEM && isHeadlessSystemUser()) { |
| // System User doesn't associate with real person, can not be switched to. |
| return false; |
| } |
| if (!canCurrentProcessSwitchUsers()) { |
| return false; |
| } |
| if (id == getCurrentForegroundUserId()) { |
| return false; |
| } |
| return mActivityManager.switchUser(id); |
| } |
| |
| /** |
| * Switches (logs in) to another user. |
| * |
| * @param userInfo User to switch to. |
| * @return {@code true} if user switching succeed. |
| */ |
| public boolean switchToUser(UserInfo userInfo) { |
| return switchToUserId(userInfo.id); |
| } |
| |
| /** |
| * Creates a new guest or finds the existing one, and switches into it. |
| * |
| * @param guestName Username for the guest user. |
| * @return {@code true} if switch to guest user succeed. |
| */ |
| public boolean startGuestSession(String guestName) { |
| UserInfo guest = createNewOrFindExistingGuest(guestName); |
| if (guest == null) { |
| return false; |
| } |
| return switchToUserId(guest.id); |
| } |
| |
| /** |
| * Creates and returns a new guest user or returns the existing one. |
| * Returns null if it fails to create a new guest. |
| * |
| * @param guestName Username for guest if new guest is being created. |
| */ |
| @Nullable |
| public UserInfo createNewOrFindExistingGuest(String guestName) { |
| // CreateGuest will return null if a guest already exists. |
| UserInfo newGuest = mUserManager.createGuest(mContext, guestName); |
| if (newGuest != null) { |
| assignDefaultIcon(newGuest); |
| return newGuest; |
| } |
| |
| UserInfo existingGuest = findExistingGuestUser(); |
| if (existingGuest == null) { |
| // Most likely a guest got removed just before we tried to look for it. |
| Log.w(TAG, "Couldn't create a new guest and couldn't find an existing one."); |
| } |
| |
| return existingGuest; |
| } |
| |
| /** |
| * Returns UserInfo for the existing guest user, or null if there are no guests on the device. |
| */ |
| @Nullable |
| private UserInfo findExistingGuestUser() { |
| for (UserInfo userInfo : getAllUsers()) { |
| if (userInfo.isGuest() && !userInfo.guestToRemove) { |
| return userInfo; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Gets a bitmap representing the user's default avatar. |
| * |
| * @param userInfo User whose avatar should be returned. |
| * @return Default user icon |
| */ |
| private Bitmap getUserDefaultIcon(UserInfo userInfo) { |
| return UserIcons.convertToBitmap( |
| UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false)); |
| } |
| |
| /** |
| * Gets a bitmap representing the default icon for a Guest user. |
| * |
| * @return Default guest user icon |
| */ |
| public Bitmap getGuestDefaultIcon() { |
| if (mDefaultGuestUserIcon == null) { |
| mDefaultGuestUserIcon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon( |
| mContext.getResources(), UserHandle.USER_NULL, false)); |
| } |
| return mDefaultGuestUserIcon; |
| } |
| |
| /** |
| * Gets an icon for the user. |
| * |
| * @param userInfo User for which we want to get the icon. |
| * @return a Bitmap for the icon |
| */ |
| public Bitmap getUserIcon(UserInfo userInfo) { |
| Bitmap picture = mUserManager.getUserIcon(userInfo.id); |
| |
| if (picture == null) { |
| return assignDefaultIcon(userInfo); |
| } |
| |
| return picture; |
| } |
| |
| /** |
| * Assigns a default icon to a user according to the user's id. |
| * |
| * @param userInfo User whose avatar is set to default icon. |
| * @return Bitmap of the user icon. |
| */ |
| public Bitmap assignDefaultIcon(UserInfo userInfo) { |
| Bitmap bitmap = userInfo.isGuest() |
| ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo); |
| mUserManager.setUserIcon(userInfo.id, bitmap); |
| return bitmap; |
| } |
| |
| private String getDefaultAdminName() { |
| if (TextUtils.isEmpty(mDefaultAdminName)) { |
| mDefaultAdminName = mContext.getString(com.android.internal.R.string.owner_name); |
| } |
| return mDefaultAdminName; |
| } |
| |
| @VisibleForTesting |
| void setDefaultAdminName(String defaultAdminName) { |
| mDefaultAdminName = defaultAdminName; |
| } |
| } |