diff options
| author | 2018-03-21 19:34:32 +0000 | |
|---|---|---|
| committer | 2018-03-21 19:34:32 +0000 | |
| commit | c7034f7ab11066a6cfa1a683df4cb46c524794dc (patch) | |
| tree | 6766c493f3d658ff631b52fc83439e6a58e8f69d | |
| parent | 1948f203123715c24dda058c0a7b35166f4db8c0 (diff) | |
| parent | 10a5d7fe22479b792698c4f1afad9ca2469afd17 (diff) | |
Merge "Adding UserManagerHelper class to SettingsLib." into pi-dev
| -rw-r--r-- | packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java | 367 | ||||
| -rw-r--r-- | packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java | 318 |
2 files changed, 685 insertions, 0 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java new file mode 100644 index 000000000000..cc69e0ec2831 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java @@ -0,0 +1,367 @@ +/* + * 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 com.android.settingslib.users; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import com.android.internal.util.UserIcons; + +import java.util.Iterator; +import java.util.List; + +/** + * Helper class for managing users, providing methods for removing, adding and switching users. + */ +public final class UserManagerHelper { + private static final String TAG = "UserManagerHelper"; + private final Context mContext; + private final UserManager mUserManager; + private OnUsersUpdateListener mUpdateListener; + private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mUpdateListener.onUsersUpdate(); + } + }; + + public UserManagerHelper(Context context) { + mContext = context; + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + + /** + * Registers a listener for updates to all users - removing, adding users or changing user info. + * + * @param listener Instance of {@link OnUsersUpdateListener}. + */ + public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) { + mUpdateListener = listener; + registerReceiver(); + } + + /** + * Unregisters listener by unregistering {@code BroadcastReceiver}. + */ + public void unregisterOnUsersUpdateListener() { + unregisterReceiver(); + } + + /** + * Gets {@link UserInfo} for the current user. + * + * @return {@link UserInfo} for the current user. + */ + public UserInfo getCurrentUserInfo() { + return mUserManager.getUserInfo(UserHandle.myUserId()); + } + + /** + * Gets all the other users on the system that are not the current user. + * + * @return List of {@code UserInfo} for each user that is not the current user. + */ + public List<UserInfo> getAllUsersExcludesCurrentUser() { + List<UserInfo> others = mUserManager.getUsers(true); + + for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) { + UserInfo userInfo = iterator.next(); + if (userInfo.id == UserHandle.myUserId()) { + // Remove current user from the list. + iterator.remove(); + } + } + return others; + } + + // User information accessors + + /** + * Checks whether the user is system user (admin). + * + * @param userInfo User to check against system user. + * @return {@code true} if system user, {@code false} otherwise. + */ + public boolean userIsSystemUser(UserInfo userInfo) { + return userInfo.id == UserHandle.USER_SYSTEM; + } + + /** + * Returns whether this user can be removed from the system. + * + * @param userInfo User to be removed + * @return {@code true} if they can be removed, {@code false} otherwise. + */ + public boolean userCanBeRemoved(UserInfo userInfo) { + return !userIsSystemUser(userInfo); + } + + /** + * Checks whether passed in user is the user that's currently logged in. + * + * @param userInfo User to check. + * @return {@code true} if current user, {@code false} otherwise. + */ + public boolean userIsCurrentUser(UserInfo userInfo) { + return getCurrentUserInfo().id == userInfo.id; + } + + // Current user information accessors + + /** + * Checks if the current user is a demo user. + */ + public boolean isDemoUser() { + return mUserManager.isDemoUser(); + } + + /** + * Checks if the current user is a guest user. + */ + public boolean isGuestUser() { + return mUserManager.isGuestUser(); + } + + /** + * Checks if the current user is the system user (User 0). + */ + public boolean isSystemUser() { + return mUserManager.isSystemUser(); + } + + // Current user restriction accessors + + /** + * Return whether the current user has a restriction. + * + * @param restriction Restriction to check. Should be a UserManager.* restriction. + * @return Whether that restriction exists for the current user. + */ + public boolean hasUserRestriction(String restriction) { + return mUserManager.hasUserRestriction(restriction); + } + + /** + * Checks if the current user can add new users. + */ + public boolean canAddUsers() { + return !hasUserRestriction(UserManager.DISALLOW_ADD_USER); + } + + /** + * Checks if the current user can remove users. + */ + public boolean canRemoveUsers() { + return !hasUserRestriction(UserManager.DISALLOW_REMOVE_USER); + } + + /** + * Checks if the current user is allowed to switch to another user. + */ + public boolean canSwitchUsers() { + return !hasUserRestriction(UserManager.DISALLOW_USER_SWITCH); + } + + /** + * Checks if the current user can modify accounts. Demo and Guest users cannot modify accounts + * even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied. + */ + public boolean canModifyAccounts() { + return !hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS) && !isDemoUser() + && !isGuestUser(); + } + + // User actions + + /** + * Creates a new user on the system. + * + * @param userName Name to give to the newly created user. + * @return Newly created user. + */ + public UserInfo createNewUser(String userName) { + UserInfo user = mUserManager.createUser(userName, 0 /* flags */); + if (user == null) { + // Couldn't create user, most likely because there are too many, but we haven't + // been able to reload the list yet. + Log.w(TAG, "can't create user."); + return null; + } + assignDefaultIcon(user); + return user; + } + + /** + * Tries to remove the user that's passed in. System user cannot be removed. + * If the user to be removed is current user, it switches to the system user first, and then + * removes the user. + * + * @param userInfo User to be removed + * @return {@code true} if user is successfully removed, {@code false} otherwise. + */ + public boolean removeUser(UserInfo userInfo) { + if (userInfo.id == UserHandle.USER_SYSTEM) { + Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed."); + return false; + } + + if (userInfo.id == getCurrentUserInfo().id) { + switchToUserId(UserHandle.USER_SYSTEM); + } + + return mUserManager.removeUser(userInfo.id); + } + + /** + * Switches (logs in) to another user. + * + * @param userInfo User to switch to. + */ + public void switchToUser(UserInfo userInfo) { + if (userInfo.id == getCurrentUserInfo().id) { + return; + } + + if (userInfo.isGuest()) { + switchToGuest(userInfo.name); + return; + } + + if (UserManager.isGuestUserEphemeral()) { + // If switching from guest, we want to bring up the guest exit dialog instead of + // switching + UserInfo currUserInfo = getCurrentUserInfo(); + if (currUserInfo != null && currUserInfo.isGuest()) { + return; + } + } + + switchToUserId(userInfo.id); + } + + /** + * Creates a guest session and switches into the guest session. + * + * @param guestName Username for the guest user. + */ + public void switchToGuest(String guestName) { + UserInfo guest = mUserManager.createGuest(mContext, guestName); + if (guest == null) { + // Couldn't create user, most likely because there are too many, but we haven't + // been able to reload the list yet. + Log.w(TAG, "can't create user."); + return; + } + switchToUserId(guest.id); + } + + /** + * 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; + } + + /** + * Method for scaling a Bitmap icon to a desirable size. + * + * @param icon Bitmap to scale. + * @param desiredSize Wanted size for the icon. + * @return Drawable for the icon, scaled to the new size. + */ + public Drawable scaleUserIcon(Bitmap icon, int desiredSize) { + Bitmap scaledIcon = Bitmap.createScaledBitmap( + icon, desiredSize, desiredSize, true /* filter */); + return new BitmapDrawable(mContext.getResources(), scaledIcon); + } + + /** + * Sets new Username for the user. + * + * @param user User whose name should be changed. + * @param name New username. + */ + public void setUserName(UserInfo user, String name) { + mUserManager.setUserName(user.id, name); + } + + private void registerReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_ADDED); + filter.addAction(Intent.ACTION_USER_INFO_CHANGED); + mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null); + } + + /** + * Assigns a default icon to a user according to the user's id. + * + * @param userInfo User to assign a default icon to. + * @return Bitmap that has been assigned to the user. + */ + private Bitmap assignDefaultIcon(UserInfo userInfo) { + Bitmap bitmap = UserIcons.convertToBitmap( + UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false)); + mUserManager.setUserIcon(userInfo.id, bitmap); + return bitmap; + } + + private void switchToUserId(int id) { + try { + final ActivityManager am = (ActivityManager) + mContext.getSystemService(Context.ACTIVITY_SERVICE); + am.switchUser(id); + } catch (Exception e) { + Log.e(TAG, "Couldn't switch user.", e); + } + } + + private void unregisterReceiver() { + mContext.unregisterReceiver(mUserChangeReceiver); + } + + /** + * Interface for listeners that want to register for receiving updates to changes to the users + * on the system including removing and adding users, and changing user info. + */ + public interface OnUsersUpdateListener { + /** + * Method that will get called when users list has been changed. + */ + void onUsersUpdate(); + } +} + diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java new file mode 100644 index 000000000000..325ef3a68aa6 --- /dev/null +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java @@ -0,0 +1,318 @@ +/* + * 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 com.android.settingslib.users; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class UserManagerHelperTest { + @Mock + private Context mContext; + @Mock + private UserManager mUserManager; + @Mock + private ActivityManager mActivityManager; + @Mock + private UserManagerHelper.OnUsersUpdateListener mTestListener; + + private UserManagerHelper mHelper; + private UserInfo mCurrentUser; + private UserInfo mSystemUser; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager); + when(mContext.getResources()) + .thenReturn(InstrumentationRegistry.getTargetContext().getResources()); + mHelper = new UserManagerHelper(mContext); + + mCurrentUser = createUserInfoForId(UserHandle.myUserId()); + mSystemUser = createUserInfoForId(UserHandle.USER_SYSTEM); + when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(mCurrentUser); + } + + @Test + public void testUserIsSystemUser() { + UserInfo testInfo = new UserInfo(); + + testInfo.id = UserHandle.USER_SYSTEM; + assertThat(mHelper.userIsSystemUser(testInfo)).isTrue(); + + testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id. + assertThat(mHelper.userIsSystemUser(testInfo)).isFalse(); + } + + @Test + public void testGetAllUsersExcludesCurrentUser() { + int currentUser = UserHandle.myUserId(); + + UserInfo otherUser1 = createUserInfoForId(currentUser + 1); + UserInfo otherUser2 = createUserInfoForId(currentUser - 1); + UserInfo otherUser3 = createUserInfoForId(currentUser + 2); + + List<UserInfo> testUsers = new ArrayList<>(); + testUsers.add(otherUser1); + testUsers.add(otherUser2); + testUsers.add(mCurrentUser); + testUsers.add(otherUser3); + + when(mUserManager.getUsers(true)).thenReturn(testUsers); + + // Should return 3 users that don't have currentUser id. + assertThat(mHelper.getAllUsersExcludesCurrentUser().size()).isEqualTo(3); + // Should not contain current user. + assertThat(mHelper.getAllUsersExcludesCurrentUser()).doesNotContain(mCurrentUser); + // Should contain non-current users. + assertThat(mHelper.getAllUsersExcludesCurrentUser()).contains(otherUser1); + assertThat(mHelper.getAllUsersExcludesCurrentUser()).contains(otherUser2); + assertThat(mHelper.getAllUsersExcludesCurrentUser()).contains(otherUser3); + } + + @Test + public void testUserCanBeRemoved() { + UserInfo testInfo = new UserInfo(); + + // System user cannot be removed. + testInfo.id = UserHandle.USER_SYSTEM; + assertThat(mHelper.userCanBeRemoved(testInfo)).isFalse(); + + testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id. + assertThat(mHelper.userCanBeRemoved(testInfo)).isTrue(); + } + + @Test + public void testUserIsCurrentUser() { + UserInfo testInfo = new UserInfo(); + + // System user cannot be removed. + testInfo.id = UserHandle.myUserId(); + assertThat(mHelper.userIsCurrentUser(testInfo)).isTrue(); + + testInfo.id = UserHandle.myUserId() + 2; + assertThat(mHelper.userIsCurrentUser(testInfo)).isFalse(); + } + + @Test + public void testCanAddUsers() { + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(false); + assertThat(mHelper.canAddUsers()).isTrue(); + + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(true); + assertThat(mHelper.canAddUsers()).isFalse(); + } + + @Test + public void testCanRemoveUsers() { + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(false); + assertThat(mHelper.canRemoveUsers()).isTrue(); + + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(true); + assertThat(mHelper.canRemoveUsers()).isFalse(); + } + + @Test + public void testCanSwitchUsers() { + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false); + assertThat(mHelper.canSwitchUsers()).isTrue(); + + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true); + assertThat(mHelper.canSwitchUsers()).isFalse(); + } + + @Test + public void testGuestCannotModifyAccounts() { + assertThat(mHelper.canModifyAccounts()).isTrue(); + + when(mUserManager.isGuestUser()).thenReturn(true); + assertThat(mHelper.canModifyAccounts()).isFalse(); + } + + @Test + public void testDemoUserCannotModifyAccounts() { + assertThat(mHelper.canModifyAccounts()).isTrue(); + + when(mUserManager.isDemoUser()).thenReturn(true); + assertThat(mHelper.canModifyAccounts()).isFalse(); + } + + @Test + public void testUserWithDisallowModifyAccountsRestrictionCannotModifyAccounts() { + assertThat(mHelper.canModifyAccounts()).isTrue(); + + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) + .thenReturn(true); + assertThat(mHelper.canModifyAccounts()).isFalse(); + } + + @Test + public void testCreateNewUser() { + // Verify createUser on UserManager gets called. + mHelper.createNewUser("Test User"); + verify(mUserManager).createUser("Test User", 0); + + when(mUserManager.createUser("Test User", 0)).thenReturn(null); + assertThat(mHelper.createNewUser("Test User")).isNull(); + + UserInfo newUser = new UserInfo(); + newUser.name = "Test User"; + when(mUserManager.createUser("Test User", 0)).thenReturn(newUser); + assertThat(mHelper.createNewUser("Test User")).isEqualTo(newUser); + } + + @Test + public void testRemoveUser() { + // Cannot remove system user. + assertThat(mHelper.removeUser(mSystemUser)).isFalse(); + + // Removing current user, calls "switch" to system user. + mHelper.removeUser(mCurrentUser); + verify(mActivityManager).switchUser(UserHandle.USER_SYSTEM); + verify(mUserManager).removeUser(mCurrentUser.id); + + // Removing non-current, non-system user, simply calls removeUser. + UserInfo userToRemove = createUserInfoForId(mCurrentUser.id + 2); + mHelper.removeUser(userToRemove); + verify(mUserManager).removeUser(mCurrentUser.id + 2); + } + + @Test + public void testSwitchToUser() { + // Switching to current user doesn't do anything. + mHelper.switchToUser(mCurrentUser); + verify(mActivityManager, never()).switchUser(mCurrentUser.id); + + // Switching to Guest calls createGuest. + UserInfo guestInfo = new UserInfo(mCurrentUser.id + 1, "Test Guest", UserInfo.FLAG_GUEST); + mHelper.switchToUser(guestInfo); + verify(mUserManager).createGuest(mContext, "Test Guest"); + + // Switching to non-current, non-guest user, simply calls switchUser. + UserInfo userToSwitchTo = new UserInfo(mCurrentUser.id + 5, "Test User", 0); + mHelper.switchToUser(userToSwitchTo); + verify(mActivityManager).switchUser(mCurrentUser.id + 5); + } + + @Test + public void testSwitchToGuest() { + mHelper.switchToGuest("Test Guest"); + verify(mUserManager).createGuest(mContext, "Test Guest"); + + UserInfo guestInfo = new UserInfo(mCurrentUser.id + 2, "Test Guest", UserInfo.FLAG_GUEST); + when(mUserManager.createGuest(mContext, "Test Guest")).thenReturn(guestInfo); + mHelper.switchToGuest("Test Guest"); + verify(mActivityManager).switchUser(mCurrentUser.id + 2); + } + + @Test + public void testGetUserIcon() { + mHelper.getUserIcon(mCurrentUser); + verify(mUserManager).getUserIcon(mCurrentUser.id); + } + + @Test + public void testScaleUserIcon() { + Bitmap fakeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + Drawable scaledIcon = mHelper.scaleUserIcon(fakeIcon, 300); + assertThat(scaledIcon.getIntrinsicWidth()).isEqualTo(300); + assertThat(scaledIcon.getIntrinsicHeight()).isEqualTo(300); + } + + @Test + public void testSetUserName() { + UserInfo testInfo = createUserInfoForId(mCurrentUser.id + 3); + mHelper.setUserName(testInfo, "New Test Name"); + verify(mUserManager).setUserName(mCurrentUser.id + 3, "New Test Name"); + } + + @Test + public void testRegisterUserChangeReceiver() { + mHelper.registerOnUsersUpdateListener(mTestListener); + + ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + ArgumentCaptor<UserHandle> handleCaptor = ArgumentCaptor.forClass(UserHandle.class); + ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); + ArgumentCaptor<String> permissionCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class); + + verify(mContext).registerReceiverAsUser( + receiverCaptor.capture(), + handleCaptor.capture(), + filterCaptor.capture(), + permissionCaptor.capture(), + handlerCaptor.capture()); + + // Verify we're listening to Intents from ALL users. + assertThat(handleCaptor.getValue()).isEqualTo(UserHandle.ALL); + + // Verify the presence of each intent in the filter. + // Verify the exact number of filters. Every time a new intent is added, this test should + // get updated. + assertThat(filterCaptor.getValue().countActions()).isEqualTo(3); + assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_REMOVED)).isTrue(); + assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_ADDED)).isTrue(); + assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue(); + + // Verify that calling the receiver calls the listener. + receiverCaptor.getValue().onReceive(mContext, new Intent()); + verify(mTestListener).onUsersUpdate(); + + assertThat(permissionCaptor.getValue()).isNull(); + assertThat(handlerCaptor.getValue()).isNull(); + + + // Unregister the receiver. + mHelper.unregisterOnUsersUpdateListener(); + verify(mContext).unregisterReceiver(receiverCaptor.getValue()); + } + + private UserInfo createUserInfoForId(int id) { + UserInfo userInfo = new UserInfo(); + userInfo.id = id; + return userInfo; + } +} |