• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CarUserManagerHelper(Context context)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      */
registerOnUsersUpdateListener(OnUsersUpdateListener listener)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      */
unregisterOnUsersUpdateListener()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      */
isHeadlessSystemUser()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      */
getSystemUserInfo()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      */
getCurrentForegroundUserInfo()119     public UserInfo getCurrentForegroundUserInfo() {
120         return mUserManager.getUserInfo(getCurrentForegroundUserId());
121     }
122 
123     /**
124      * @return Id of the current foreground user.
125      */
getCurrentForegroundUserId()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      */
getCurrentProcessUserInfo()142     public UserInfo getCurrentProcessUserInfo() {
143         return mUserManager.getUserInfo(getCurrentProcessUserId());
144     }
145 
146     /**
147      * @return Id for the user running the current process.
148      */
getCurrentProcessUserId()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      */
getAllSwitchableUsers()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      */
getAllUsers()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      */
getAllUsersExceptSpecifiedUser(int userId)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      */
getAllUsersExceptSystemUserAndSpecifiedUser(int userId)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      */
isSystemUser(UserInfo userInfo)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      */
isDefaultUser(UserInfo userInfo)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      */
isForegroundUser(UserInfo userInfo)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      */
isCurrentProcessUser(UserInfo userInfo)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      */
isForegroundUserGuest()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      */
canUserBeRemoved(UserInfo userInfo)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      */
foregroundUserHasUserRestriction(String restriction)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      */
canForegroundUserAddUsers()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      */
isCurrentProcessSystemUser()302     public boolean isCurrentProcessSystemUser() {
303         return mUserManager.isSystemUser();
304     }
305 
306     /**
307      * Checks if the calling app is running in a demo user.
308      */
isCurrentProcessDemoUser()309     public boolean isCurrentProcessDemoUser() {
310         return mUserManager.isDemoUser();
311     }
312 
313     /**
314      * Checks if the calling app is running as a guest user.
315      */
isCurrentProcessGuestUser()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      */
isCurrentProcessRestrictedProfileUser()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      */
isCurrentProcessUserHasRestriction(String restriction)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      */
canCurrentProcessModifyAccounts()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      */
canCurrentProcessAddUsers()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      */
canCurrentProcessRemoveUsers()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      */
canCurrentProcessSwitchUsers()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
createNewAdminUser(String userName)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
createNewNonAdminUser(String userName)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      */
removeUser(UserInfo userInfo, String guestUserName)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      */
switchToUserId(int id)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      */
switchToUser(UserInfo userInfo)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      */
startNewGuestSession(String guestName)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      */
getUserDefaultIcon(UserInfo userInfo)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      */
getGuestDefaultIcon()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      */
getUserIcon(UserInfo userInfo)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      */
scaleUserIcon(Bitmap icon, int desiredSize)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      */
setUserName(UserInfo user, String name)542     public void setUserName(UserInfo user, String name) {
543         mUserManager.setUserName(user.id, name);
544     }
545 
registerReceiver()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.
assignDefaultIcon(UserInfo userInfo)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 
unregisterReceiver()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          */
onUsersUpdate()577         void onUsersUpdate();
578     }
579 }
580