Home | History | Annotate | Download | only in user
      1 /*
      2  * Copyright (C) 2018 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 package android.car.user;
     17 
     18 import android.annotation.Nullable;
     19 import android.app.ActivityManager;
     20 import android.car.settings.CarSettings;
     21 import android.content.BroadcastReceiver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.content.pm.UserInfo;
     26 import android.graphics.Bitmap;
     27 import android.graphics.drawable.BitmapDrawable;
     28 import android.graphics.drawable.Drawable;
     29 import android.os.SystemProperties;
     30 import android.os.UserHandle;
     31 import android.os.UserManager;
     32 import android.util.Log;
     33 
     34 import com.android.internal.util.UserIcons;
     35 
     36 import java.util.Iterator;
     37 import java.util.List;
     38 
     39 /**
     40  * Helper class for {@link UserManager}, this is meant to be used by builds that support
     41  * Multi-user model with headless user 0. User 0 is not associated with a real person, and
     42  * can not be brought to foreground.
     43  *
     44  * <p>This class provides method for user management, including creating, removing, adding
     45  * and switching users. Methods related to get users will exclude system user by default.
     46  *
     47  * @hide
     48  */
     49 public class CarUserManagerHelper {
     50     private static final String TAG = "CarUserManagerHelper";
     51     private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless";
     52     private final Context mContext;
     53     private final UserManager mUserManager;
     54     private final ActivityManager mActivityManager;
     55     private Bitmap mDefaultGuestUserIcon;
     56     private OnUsersUpdateListener mUpdateListener;
     57     private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
     58         @Override
     59         public void onReceive(Context context, Intent intent) {
     60             mUpdateListener.onUsersUpdate();
     61         }
     62     };
     63 
     64     public CarUserManagerHelper(Context context) {
     65         mContext = context.getApplicationContext();
     66         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
     67         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
     68     }
     69 
     70     /**
     71      * Registers a listener for updates to all users - removing, adding users or changing user info.
     72      *
     73      * <p> Best practise is to keep one listener per helper.
     74      *
     75      * @param listener Instance of {@link OnUsersUpdateListener}.
     76      */
     77     public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) {
     78         if (mUpdateListener != null) {
     79             unregisterOnUsersUpdateListener();
     80         }
     81 
     82         mUpdateListener = listener;
     83         registerReceiver();
     84     }
     85 
     86     /**
     87      * Unregisters on user update listener by unregistering {@code BroadcastReceiver}.
     88      */
     89     public void unregisterOnUsersUpdateListener() {
     90         unregisterReceiver();
     91     }
     92 
     93     /**
     94      * Returns {@code true} if the system is in the headless user 0 model.
     95      *
     96      * @return {@boolean true} if headless system user.
     97      */
     98     public boolean isHeadlessSystemUser() {
     99         return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false);
    100     }
    101 
    102     /**
    103      * Gets UserInfo for the system user.
    104      *
    105      * @return {@link UserInfo} for the system user.
    106      */
    107     public UserInfo getSystemUserInfo() {
    108         return mUserManager.getUserInfo(UserHandle.USER_SYSTEM);
    109     }
    110 
    111     /**
    112      * Gets UserInfo for the current foreground user.
    113      *
    114      * Concept of foreground user is relevant for the multi-user deployment. Foreground user
    115      * corresponds to the currently "logged in" user.
    116      *
    117      * @return {@link UserInfo} for the foreground user.
    118      */
    119     public UserInfo getCurrentForegroundUserInfo() {
    120         return mUserManager.getUserInfo(getCurrentForegroundUserId());
    121     }
    122 
    123     /**
    124      * @return Id of the current foreground user.
    125      */
    126     public int getCurrentForegroundUserId() {
    127         return mActivityManager.getCurrentUser();
    128     }
    129 
    130     /**
    131      * Gets UserInfo for the user running the caller process.
    132      *
    133      * <p>Differentiation between foreground user and current process user is relevant for
    134      * multi-user deployments.
    135      *
    136      * <p>Some multi-user aware components (like SystemUI) needs to run a singleton component
    137      * in system user. Current process user is always the same for that component, even when
    138      * the foreground user changes.
    139      *
    140      * @return {@link UserInfo} for the user running the current process.
    141      */
    142     public UserInfo getCurrentProcessUserInfo() {
    143         return mUserManager.getUserInfo(getCurrentProcessUserId());
    144     }
    145 
    146     /**
    147      * @return Id for the user running the current process.
    148      */
    149     public int getCurrentProcessUserId() {
    150         return UserHandle.myUserId();
    151     }
    152 
    153     /**
    154      * Gets all the existing foreground users on the system that are not currently running as
    155      * the foreground user.
    156      *
    157      * @return List of {@code UserInfo} for each user that is not the foreground user.
    158      */
    159     public List<UserInfo> getAllSwitchableUsers() {
    160         if (isHeadlessSystemUser()) {
    161             return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId());
    162         } else {
    163             return getAllUsersExceptSpecifiedUser(getCurrentForegroundUserId());
    164         }
    165     }
    166 
    167     /**
    168      * Gets all the users that can be brought to the foreground on the system.
    169      *
    170      * @return List of {@code UserInfo} for users that associated with a real person.
    171      */
    172     public List<UserInfo> getAllUsers() {
    173         if (isHeadlessSystemUser()) {
    174             return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM);
    175         } else {
    176             return mUserManager.getUsers(/* excludeDying= */true);
    177         }
    178     }
    179 
    180     /**
    181      * Get all the users except the one with userId passed in.
    182      *
    183      * @param userId of the user not to be returned.
    184      * @return All users other than user with userId.
    185      */
    186     private List<UserInfo> getAllUsersExceptSpecifiedUser(int userId) {
    187         List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
    188 
    189         for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
    190             UserInfo userInfo = iterator.next();
    191             if (userInfo.id == userId) {
    192                 // Remove user with userId from the list.
    193                 iterator.remove();
    194             }
    195         }
    196         return users;
    197     }
    198 
    199     /**
    200      * Get all the users except system user and the one with userId passed in.
    201      *
    202      * @param userId of the user not to be returned.
    203      * @return All users other than system user and user with userId.
    204      */
    205     private List<UserInfo> getAllUsersExceptSystemUserAndSpecifiedUser(int userId) {
    206         List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
    207 
    208         for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
    209             UserInfo userInfo = iterator.next();
    210             if (userInfo.id == userId || userInfo.id == UserHandle.USER_SYSTEM) {
    211                 // Remove user with userId from the list.
    212                 iterator.remove();
    213             }
    214         }
    215         return users;
    216     }
    217 
    218     // User information accessors
    219 
    220     /**
    221      * Checks whether the user is system user.
    222      *
    223      * @param userInfo User to check against system user.
    224      * @return {@code true} if system user, {@code false} otherwise.
    225      */
    226     public boolean isSystemUser(UserInfo userInfo) {
    227         return userInfo.id == UserHandle.USER_SYSTEM;
    228     }
    229 
    230     /**
    231      * Checks whether the user is default user.
    232      *
    233      * @param userInfo User to check against system user.
    234      * @return {@code true} if is default user, {@code false} otherwise.
    235      */
    236     public boolean isDefaultUser(UserInfo userInfo) {
    237         return userInfo.id == CarSettings.DEFAULT_USER_ID_TO_BOOT_INTO;
    238     }
    239 
    240     /**
    241      * Checks whether passed in user is the foreground user.
    242      *
    243      * @param userInfo User to check.
    244      * @return {@code true} if foreground user, {@code false} otherwise.
    245      */
    246     public boolean isForegroundUser(UserInfo userInfo) {
    247         return getCurrentForegroundUserId() == userInfo.id;
    248     }
    249 
    250     /**
    251      * Checks whether passed in user is the user that's running the current process.
    252      *
    253      * @param userInfo User to check.
    254      * @return {@code true} if user running the process, {@code false} otherwise.
    255      */
    256     public boolean isCurrentProcessUser(UserInfo userInfo) {
    257         return getCurrentProcessUserId() == userInfo.id;
    258     }
    259 
    260     // Foreground user information accessors.
    261 
    262     /**
    263      * Checks if the foreground user is a guest user.
    264      */
    265     public boolean isForegroundUserGuest() {
    266         return getCurrentForegroundUserInfo().isGuest();
    267     }
    268 
    269     /**
    270      * Returns whether this user can be removed from the system.
    271      *
    272      * @param userInfo User to be removed
    273      * @return {@code true} if they can be removed, {@code false} otherwise.
    274      */
    275     public boolean canUserBeRemoved(UserInfo userInfo) {
    276         return !isSystemUser(userInfo);
    277     }
    278 
    279     /**
    280      * Return whether the foreground user has a restriction.
    281      *
    282      * @param restriction Restriction to check. Should be a UserManager.* restriction.
    283      * @return Whether that restriction exists for the foreground user.
    284      */
    285     public boolean foregroundUserHasUserRestriction(String restriction) {
    286         return mUserManager.hasUserRestriction(
    287             restriction, getCurrentForegroundUserInfo().getUserHandle());
    288     }
    289 
    290     /**
    291      * Checks if the foreground user can add new users.
    292      */
    293     public boolean canForegroundUserAddUsers() {
    294         return !foregroundUserHasUserRestriction(UserManager.DISALLOW_ADD_USER);
    295     }
    296 
    297     // Current process user information accessors
    298 
    299     /**
    300      * Checks whether this process is running under the system user.
    301      */
    302     public boolean isCurrentProcessSystemUser() {
    303         return mUserManager.isSystemUser();
    304     }
    305 
    306     /**
    307      * Checks if the calling app is running in a demo user.
    308      */
    309     public boolean isCurrentProcessDemoUser() {
    310         return mUserManager.isDemoUser();
    311     }
    312 
    313     /**
    314      * Checks if the calling app is running as a guest user.
    315      */
    316     public boolean isCurrentProcessGuestUser() {
    317         return mUserManager.isGuestUser();
    318     }
    319 
    320     /**
    321      * Check is the calling app is running as a restricted profile user (ie. a LinkedUser).
    322      * Restricted profiles are only available when {@link #isHeadlessSystemUser()} is false.
    323      */
    324     public boolean isCurrentProcessRestrictedProfileUser() {
    325         return mUserManager.isRestrictedProfile();
    326     }
    327 
    328     // Current process user restriction accessors
    329 
    330     /**
    331      * Return whether the user running the current process has a restriction.
    332      *
    333      * @param restriction Restriction to check. Should be a UserManager.* restriction.
    334      * @return Whether that restriction exists for the user running the process.
    335      */
    336     public boolean isCurrentProcessUserHasRestriction(String restriction) {
    337         return mUserManager.hasUserRestriction(restriction);
    338     }
    339 
    340     /**
    341      * Checks if the current process user can modify accounts. Demo and Guest users cannot modify
    342      * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied.
    343      */
    344     public boolean canCurrentProcessModifyAccounts() {
    345         return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)
    346             && !isCurrentProcessDemoUser()
    347             && !isCurrentProcessGuestUser();
    348     }
    349 
    350     /**
    351      * Checks if the user running the current process can add new users.
    352      */
    353     public boolean canCurrentProcessAddUsers() {
    354         return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_ADD_USER);
    355     }
    356 
    357     /**
    358      * Checks if the user running the current process can remove users.
    359      */
    360     public boolean canCurrentProcessRemoveUsers() {
    361         return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_REMOVE_USER);
    362     }
    363 
    364     /**
    365      * Checks if the user running the current process is allowed to switch to another user.
    366      */
    367     public boolean canCurrentProcessSwitchUsers() {
    368         return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_USER_SWITCH);
    369     }
    370 
    371     /**
    372      * Creates a new user on the system, the created user would be granted admin role.
    373      *
    374      * @param userName Name to give to the newly created user.
    375      * @return Newly created admin user, null if failed to create a user.
    376      */
    377     @Nullable
    378     public UserInfo createNewAdminUser(String userName) {
    379         UserInfo user = mUserManager.createUser(userName, UserInfo.FLAG_ADMIN);
    380         if (user == null) {
    381             // Couldn't create user, most likely because there are too many, but we haven't
    382             // been able to reload the list yet.
    383             Log.w(TAG, "can't create admin user.");
    384             return null;
    385         }
    386         assignDefaultIcon(user);
    387         return user;
    388     }
    389 
    390     /**
    391      * Creates a new restricted user on the system.
    392      *
    393      * @param userName Name to give to the newly created user.
    394      * @return Newly created restricted user, null if failed to create a user.
    395      */
    396     @Nullable
    397     public UserInfo createNewNonAdminUser(String userName) {
    398         UserInfo user = mUserManager.createUser(userName, 0);
    399         if (user == null) {
    400             // Couldn't create user, most likely because there are too many, but we haven't
    401             // been able to reload the list yet.
    402             Log.w(TAG, "can't create non-admin user.");
    403             return null;
    404         }
    405         assignDefaultIcon(user);
    406         return user;
    407     }
    408 
    409     /**
    410      * Tries to remove the user that's passed in. System user cannot be removed.
    411      * If the user to be removed is user currently running the process,
    412      * it switches to the guest user first, and then removes the user.
    413      *
    414      * @param userInfo User to be removed
    415      * @return {@code true} if user is successfully removed, {@code false} otherwise.
    416      */
    417     public boolean removeUser(UserInfo userInfo, String guestUserName) {
    418         if (isSystemUser(userInfo)) {
    419             Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed.");
    420             return false;
    421         }
    422 
    423         // Not allow to delete the default user for now. Since default user is the one to
    424         // boot into.
    425         if (isHeadlessSystemUser() && isDefaultUser(userInfo)) {
    426             Log.w(TAG, "User " + userInfo.id + " is the default user, could not be removed.");
    427             return false;
    428         }
    429 
    430         if (userInfo.id == getCurrentForegroundUserId()) {
    431             startNewGuestSession(guestUserName);
    432         }
    433 
    434         return mUserManager.removeUser(userInfo.id);
    435     }
    436 
    437     /**
    438      * Switches (logs in) to another user given user id.
    439      *
    440      * @param id User id to switch to.
    441      * @return {@code true} if user switching succeed.
    442      */
    443     public boolean switchToUserId(int id) {
    444         if (id == UserHandle.USER_SYSTEM && isHeadlessSystemUser()) {
    445             // System User doesn't associate with real person, can not be switched to.
    446             return false;
    447         }
    448         return mActivityManager.switchUser(id);
    449     }
    450 
    451     /**
    452      * Switches (logs in) to another user.
    453      *
    454      * @param userInfo User to switch to.
    455      * @return {@code true} if user switching succeed.
    456      */
    457     public boolean switchToUser(UserInfo userInfo) {
    458         if (userInfo.id == getCurrentForegroundUserId()) {
    459             return false;
    460         }
    461 
    462         return switchToUserId(userInfo.id);
    463     }
    464 
    465     /**
    466      * Creates a new guest session and switches into the guest session.
    467      *
    468      * @param guestName Username for the guest user.
    469      * @return {@code true} if switch to guest user succeed.
    470      */
    471     public boolean startNewGuestSession(String guestName) {
    472         UserInfo guest = mUserManager.createGuest(mContext, guestName);
    473         if (guest == null) {
    474             // Couldn't create user, most likely because there are too many, but we haven't
    475             // been able to reload the list yet.
    476             Log.w(TAG, "can't create user.");
    477             return false;
    478         }
    479         assignDefaultIcon(guest);
    480         return switchToUserId(guest.id);
    481     }
    482 
    483     /**
    484      * Gets a bitmap representing the user's default avatar.
    485      *
    486      * @param userInfo User whose avatar should be returned.
    487      * @return Default user icon
    488      */
    489     public Bitmap getUserDefaultIcon(UserInfo userInfo) {
    490         return UserIcons.convertToBitmap(
    491             UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false));
    492     }
    493 
    494     /**
    495      * Gets a bitmap representing the default icon for a Guest user.
    496      *
    497      * @return Default guest user icon
    498      */
    499     public Bitmap getGuestDefaultIcon() {
    500         if (mDefaultGuestUserIcon == null) {
    501             mDefaultGuestUserIcon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
    502                 mContext.getResources(), UserHandle.USER_NULL, false));
    503         }
    504         return mDefaultGuestUserIcon;
    505     }
    506 
    507     /**
    508      * Gets an icon for the user.
    509      *
    510      * @param userInfo User for which we want to get the icon.
    511      * @return a Bitmap for the icon
    512      */
    513     public Bitmap getUserIcon(UserInfo userInfo) {
    514         Bitmap picture = mUserManager.getUserIcon(userInfo.id);
    515 
    516         if (picture == null) {
    517             return assignDefaultIcon(userInfo);
    518         }
    519 
    520         return picture;
    521     }
    522 
    523     /**
    524      * Method for scaling a Bitmap icon to a desirable size.
    525      *
    526      * @param icon Bitmap to scale.
    527      * @param desiredSize Wanted size for the icon.
    528      * @return Drawable for the icon, scaled to the new size.
    529      */
    530     public Drawable scaleUserIcon(Bitmap icon, int desiredSize) {
    531         Bitmap scaledIcon = Bitmap.createScaledBitmap(
    532                 icon, desiredSize, desiredSize, true /* filter */);
    533         return new BitmapDrawable(mContext.getResources(), scaledIcon);
    534     }
    535 
    536     /**
    537      * Sets new Username for the user.
    538      *
    539      * @param user User whose name should be changed.
    540      * @param name New username.
    541      */
    542     public void setUserName(UserInfo user, String name) {
    543         mUserManager.setUserName(user.id, name);
    544     }
    545 
    546     private void registerReceiver() {
    547         IntentFilter filter = new IntentFilter();
    548         filter.addAction(Intent.ACTION_USER_REMOVED);
    549         filter.addAction(Intent.ACTION_USER_ADDED);
    550         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
    551         filter.addAction(Intent.ACTION_USER_SWITCHED);
    552         filter.addAction(Intent.ACTION_USER_STOPPED);
    553         filter.addAction(Intent.ACTION_USER_UNLOCKED);
    554         mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null);
    555     }
    556 
    557     // Assigns a default icon to a user according to the user's id.
    558     private Bitmap assignDefaultIcon(UserInfo userInfo) {
    559         Bitmap bitmap = userInfo.isGuest()
    560                 ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo);
    561         mUserManager.setUserIcon(userInfo.id, bitmap);
    562         return bitmap;
    563     }
    564 
    565     private void unregisterReceiver() {
    566         mContext.unregisterReceiver(mUserChangeReceiver);
    567     }
    568 
    569     /**
    570      * Interface for listeners that want to register for receiving updates to changes to the users
    571      * on the system including removing and adding users, and changing user info.
    572      */
    573     public interface OnUsersUpdateListener {
    574         /**
    575          * Method that will get called when users list has been changed.
    576          */
    577         void onUsersUpdate();
    578     }
    579 }
    580