diff options
author | Ying Zheng <yizheng@google.com> | 2018-06-19 16:01:05 -0700 |
---|---|---|
committer | Ying Zheng <yizheng@google.com> | 2018-06-20 16:42:07 -0700 |
commit | f4339b8cb132a3b6635f4516eb7f65cf8e074fe7 (patch) | |
tree | a0b8c826ec1b60d6a2cc0ff791e71dc9f78f7258 | |
parent | d812d4c1ac4590e98d41c01fab14f654ea0b3657 (diff) | |
download | Car-f4339b8cb132a3b6635f4516eb7f65cf8e074fe7.tar.gz |
Complete the logic around last active user, including:
- Update CarSettings last active user when user switched.
- Boot into the last active user if valid, or boot into the smallest
user id.
- Not allow deleting the last admin user, so we have a user 10+ to boot
into.
Test: Unit test
Bug: 110156344,110425490,110425354
Change-Id: I3e85805bf469bd17709973936e8c3285c8f44207
4 files changed, 329 insertions, 110 deletions
diff --git a/car-lib/src/android/car/user/CarUserManagerHelper.java b/car-lib/src/android/car/user/CarUserManagerHelper.java index 9aafdff4d1..41053536d3 100644 --- a/car-lib/src/android/car/user/CarUserManagerHelper.java +++ b/car-lib/src/android/car/user/CarUserManagerHelper.java @@ -34,6 +34,7 @@ import android.os.UserManager; import android.provider.Settings; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.UserIcons; import com.google.android.collect.Sets; @@ -65,6 +66,7 @@ public class CarUserManagerHelper { private final Context mContext; private final UserManager mUserManager; private final ActivityManager mActivityManager; + private int mLastActiveUser = UserHandle.USER_SYSTEM; private Bitmap mDefaultGuestUserIcon; private OnUsersUpdateListener mUpdateListener; private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { @@ -107,7 +109,9 @@ public class CarUserManagerHelper { * Set default boot into user. * * @param userId default user id to boot into. + * @deprecated Setting default user is obsolete */ + @Deprecated public void setDefaultBootUser(int userId) { Settings.Global.putInt( mContext.getContentResolver(), @@ -118,17 +122,23 @@ public class CarUserManagerHelper { * Set last active user. * * @param userId last active user id. + * @param skipGlobalSetting whether to skip set the global settings value. */ - public void setLastActiveUser(int userId) { - Settings.Global.putInt( - mContext.getContentResolver(), CarSettings.Global.LAST_ACTIVE_USER_ID, userId); + public void setLastActiveUser(int userId, boolean skipGlobalSetting) { + mLastActiveUser = userId; + if (!skipGlobalSetting) { + Settings.Global.putInt( + mContext.getContentResolver(), CarSettings.Global.LAST_ACTIVE_USER_ID, userId); + } } /** * Get user id for the default boot into user. * * @return user id of the default boot into user + * @deprecated Use {@link #getLastActiveUser()} instead. */ + @Deprecated public int getDefaultBootUser() { // Make user 10 the original default boot user. return Settings.Global.getInt( @@ -139,13 +149,46 @@ public class CarUserManagerHelper { /** * Get user id for the last active user. * - * @return user id of the last active user + * @return user id of the last active user. */ public int getLastActiveUser() { - // Make user 10 the original default last active user. + if (mLastActiveUser != UserHandle.USER_SYSTEM) { + return mLastActiveUser; + } return Settings.Global.getInt( mContext.getContentResolver(), CarSettings.Global.LAST_ACTIVE_USER_ID, - /* default user id= */ 10); + /* default user id= */ UserHandle.USER_SYSTEM); + } + + /** + * Get user id for the initial user to boot into. + * + * <p>If failed to retrieve the id stored in global settings or the retrieved id does not + * exist on device, then return the user with smallest user id. + * + * @return user id of the last active user or the smallest user id on the device. + */ + public int getInitialUser() { + int lastActiveUserId = getLastActiveUser(); + + boolean isUserExist = false; + List<UserInfo> allUsers = getAllPersistentUsers(); + int smallestUserId = Integer.MAX_VALUE; + for (UserInfo user : allUsers) { + if (user.id == lastActiveUserId) { + isUserExist = true; + } + smallestUserId = Math.min(user.id, smallestUserId); + } + + // If the last active user is system user or the user id doesn't exist on device, + // return the smallest id or all users. + if (lastActiveUserId == UserHandle.USER_SYSTEM || !isUserExist) { + Log.e(TAG, "Can't get last active user id or the user no longer exist."); + lastActiveUserId = smallestUserId; + } + + return lastActiveUserId; } /** @@ -237,6 +280,41 @@ public class CarUserManagerHelper { } /** + * 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 not admin. + 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; + } + + /** * Get all the users except the one with userId passed in. * * @param userId of the user not to be returned. @@ -291,12 +369,25 @@ public class CarUserManagerHelper { * * @param userInfo User to check against system user. * @return {@code true} if is default user, {@code false} otherwise. + * + * @deprecated Default user is obsolete */ + @Deprecated public boolean isDefaultUser(UserInfo userInfo) { return userInfo.id == getDefaultBootUser(); } /** + * Checks whether the user is last active user. + * + * @param userInfo User to check against last active user. + * @return {@code true} if is last active user, {@code false} otherwise. + */ + public boolean isLastActiveUser(UserInfo userInfo) { + return userInfo.id == getLastActiveUser(); + } + + /** * Checks whether passed in user is the foreground user. * * @param userInfo User to check. @@ -544,10 +635,9 @@ public class CarUserManagerHelper { return false; } - // Not allow to delete the default user for now. Since default user is the one to - // boot into. - if (isHeadlessSystemUser() && isDefaultUser(userInfo)) { - Log.w(TAG, "User " + userInfo.id + " is the default user, could not be removed."); + // Not allow to delete the last admin user on the device for now. + if (userInfo.isAdmin() && getAllAdminUsers().size() <= 1) { + Log.w(TAG, "User " + userInfo.id + " is the last admin user on device."); return false; } diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java index a66621085b..46c762c41d 100644 --- a/service/src/com/android/car/user/CarUserService.java +++ b/service/src/com/android/car/user/CarUserService.java @@ -36,7 +36,7 @@ import java.io.PrintWriter; * * <ol> * <li> Creates a secondary admin user on first run. - * <li> Log in to a default user. + * <li> Log in to the last active user. * <ol/> */ public class CarUserService extends BroadcastReceiver implements CarServiceBase { @@ -63,6 +63,7 @@ public class CarUserService extends BroadcastReceiver implements CarServiceBase } IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED); + filter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(this, filter); } @@ -95,8 +96,19 @@ public class CarUserService extends BroadcastReceiver implements CarServiceBase // On very first boot, create an admin user and switch to that user. UserInfo admin = mCarUserManagerHelper.createNewAdminUser(OWNER_NAME); mCarUserManagerHelper.switchToUser(admin); + mCarUserManagerHelper.setLastActiveUser( + admin.id, /* skipGlobalSettings= */ false); } else { - mCarUserManagerHelper.switchToUserId(mCarUserManagerHelper.getDefaultBootUser()); + mCarUserManagerHelper.switchToUserId(mCarUserManagerHelper.getInitialUser()); + } + } + if (intent.getAction() == Intent.ACTION_USER_SWITCHED) { + UserInfo foregroundUser = mCarUserManagerHelper.getCurrentForegroundUserInfo(); + // Update last active user if foreground user is not ephemeral. + if (!foregroundUser.isEphemeral() && !foregroundUser.isGuest()) { + mCarUserManagerHelper.setLastActiveUser( + mCarUserManagerHelper.getCurrentForegroundUserId(), + /* skipGlobalSettings= */ false); } } } diff --git a/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java index 3c97ca19cc..ca6e027843 100644 --- a/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java +++ b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java @@ -19,9 +19,9 @@ package com.android.car; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.car.user.CarUserManagerHelper; @@ -40,6 +40,10 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,10 +51,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - /** * This class contains unit tests for the {@link CarUserManagerHelper}. * It tests that {@link CarUserManagerHelper} does the right thing for user management flows. @@ -73,7 +73,7 @@ public class CarUserManagerHelperTest { @Mock private CarUserManagerHelper.OnUsersUpdateListener mTestListener; - private CarUserManagerHelper mHelper; + private CarUserManagerHelper mCarUserManagerHelper; private UserInfo mCurrentProcessUser; private UserInfo mSystemUser; private String mGuestUserName = "testGuest"; @@ -84,16 +84,16 @@ public class CarUserManagerHelperTest { @Before public void setUpMocksAndVariables() 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()); - when(mContext.getApplicationContext()).thenReturn(mContext); - mHelper = new CarUserManagerHelper(mContext); + doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE); + doReturn(mActivityManager).when(mContext).getSystemService(Context.ACTIVITY_SERVICE); + doReturn(InstrumentationRegistry.getTargetContext().getResources()) + .when(mContext).getResources(); + doReturn(mContext).when(mContext).getApplicationContext(); + mCarUserManagerHelper = new CarUserManagerHelper(mContext); mCurrentProcessUser = createUserInfoForId(UserHandle.myUserId()); mSystemUser = createUserInfoForId(UserHandle.USER_SYSTEM); - when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(mCurrentProcessUser); + doReturn(mCurrentProcessUser).when(mUserManager).getUserInfo(UserHandle.myUserId()); // Get the ID of the foreground user running this test. // We cannot mock the foreground user since getCurrentUser is static. @@ -111,10 +111,10 @@ public class CarUserManagerHelperTest { UserInfo testInfo = new UserInfo(); testInfo.id = UserHandle.USER_SYSTEM; - assertThat(mHelper.isSystemUser(testInfo)).isTrue(); + assertThat(mCarUserManagerHelper.isSystemUser(testInfo)).isTrue(); testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id. - assertThat(mHelper.isSystemUser(testInfo)).isFalse(); + assertThat(mCarUserManagerHelper.isSystemUser(testInfo)).isFalse(); } // System user will not be returned when calling get all users. @@ -131,10 +131,10 @@ public class CarUserManagerHelperTest { testUsers.add(otherUser2); testUsers.add(otherUser3); - when(mUserManager.getUsers(true)).thenReturn(testUsers); + doReturn(testUsers).when(mUserManager).getUsers(true); - assertThat(mHelper.getAllUsers()).hasSize(3); - assertThat(mHelper.getAllUsers()) + assertThat(mCarUserManagerHelper.getAllUsers()).hasSize(3); + assertThat(mCarUserManagerHelper.getAllUsers()) .containsExactly(otherUser1, otherUser2, otherUser3); } @@ -146,14 +146,14 @@ public class CarUserManagerHelperTest { List<UserInfo> testUsers = Arrays.asList(mForegroundUser, user1, user2); - when(mUserManager.getUsers(true)).thenReturn(new ArrayList<>(testUsers)); + doReturn(new ArrayList<>(testUsers)).when(mUserManager).getUsers(true); // Should return all 3 users. - assertThat(mHelper.getAllUsers()).hasSize(3); + assertThat(mCarUserManagerHelper.getAllUsers()).hasSize(3); // Should return all non-foreground users. - assertThat(mHelper.getAllSwitchableUsers()).hasSize(2); - assertThat(mHelper.getAllSwitchableUsers()).containsExactly(user1, user2); + assertThat(mCarUserManagerHelper.getAllSwitchableUsers()).hasSize(2); + assertThat(mCarUserManagerHelper.getAllSwitchableUsers()).containsExactly(user1, user2); } @Test @@ -162,80 +162,89 @@ public class CarUserManagerHelperTest { // System user cannot be removed. testInfo.id = UserHandle.USER_SYSTEM; - assertThat(mHelper.canUserBeRemoved(testInfo)).isFalse(); + assertThat(mCarUserManagerHelper.canUserBeRemoved(testInfo)).isFalse(); testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id. - assertThat(mHelper.canUserBeRemoved(testInfo)).isTrue(); + assertThat(mCarUserManagerHelper.canUserBeRemoved(testInfo)).isTrue(); } @Test public void testCurrentProcessCanAddUsers() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(false); - assertThat(mHelper.canCurrentProcessAddUsers()).isTrue(); + doReturn(false).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_ADD_USER); + assertThat(mCarUserManagerHelper.canCurrentProcessAddUsers()).isTrue(); - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(true); - assertThat(mHelper.canCurrentProcessAddUsers()).isFalse(); + doReturn(true).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_ADD_USER); + assertThat(mCarUserManagerHelper.canCurrentProcessAddUsers()).isFalse(); } @Test public void testCurrentProcessCanRemoveUsers() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(false); - assertThat(mHelper.canCurrentProcessRemoveUsers()).isTrue(); + doReturn(false).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_REMOVE_USER); + assertThat(mCarUserManagerHelper.canCurrentProcessRemoveUsers()).isTrue(); - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(true); - assertThat(mHelper.canCurrentProcessRemoveUsers()).isFalse(); + doReturn(true).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_REMOVE_USER); + assertThat(mCarUserManagerHelper.canCurrentProcessRemoveUsers()).isFalse(); } @Test public void testCurrentProcessCanSwitchUsers() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false); - assertThat(mHelper.canCurrentProcessSwitchUsers()).isTrue(); + doReturn(false).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_USER_SWITCH); + assertThat(mCarUserManagerHelper.canCurrentProcessSwitchUsers()).isTrue(); - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true); - assertThat(mHelper.canCurrentProcessSwitchUsers()).isFalse(); + doReturn(true).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_USER_SWITCH); + assertThat(mCarUserManagerHelper.canCurrentProcessSwitchUsers()).isFalse(); } @Test public void testCurrentGuestProcessCannotModifyAccounts() { - assertThat(mHelper.canCurrentProcessModifyAccounts()).isTrue(); + assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue(); + + doReturn(true).when(mUserManager).isGuestUser(); - when(mUserManager.isGuestUser()).thenReturn(true); - assertThat(mHelper.canCurrentProcessModifyAccounts()).isFalse(); + assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse(); } @Test public void testCurrentDemoProcessCannotModifyAccounts() { - assertThat(mHelper.canCurrentProcessModifyAccounts()).isTrue(); + assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue(); - when(mUserManager.isDemoUser()).thenReturn(true); - assertThat(mHelper.canCurrentProcessModifyAccounts()).isFalse(); + doReturn(true).when(mUserManager).isDemoUser(); + + assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse(); } @Test public void testCurrentDisallowModifyAccountsProcessIsEnforced() { - assertThat(mHelper.canCurrentProcessModifyAccounts()).isTrue(); + assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue(); + + doReturn(true).when(mUserManager) + .hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS); - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) - .thenReturn(true); - assertThat(mHelper.canCurrentProcessModifyAccounts()).isFalse(); + assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse(); } @Test public void testCreateNewAdminUser() { // Make sure current user is admin, since only admins can create other admins. - when(mUserManager.isAdminUser()).thenReturn(true); + doReturn(true).when(mUserManager).isAdminUser(); // Verify createUser on UserManager gets called. - mHelper.createNewAdminUser(mTestUserName); + mCarUserManagerHelper.createNewAdminUser(mTestUserName); verify(mUserManager).createUser(mTestUserName, UserInfo.FLAG_ADMIN); - when(mUserManager.createUser(mTestUserName, UserInfo.FLAG_ADMIN)).thenReturn(null); - assertThat(mHelper.createNewAdminUser(mTestUserName)).isNull(); + doReturn(null).when(mUserManager).createUser(mTestUserName, UserInfo.FLAG_ADMIN); + assertThat(mCarUserManagerHelper.createNewAdminUser(mTestUserName)).isNull(); UserInfo newUser = new UserInfo(); newUser.name = mTestUserName; - when(mUserManager.createUser(mTestUserName, UserInfo.FLAG_ADMIN)).thenReturn(newUser); - assertThat(mHelper.createNewAdminUser(mTestUserName)).isEqualTo(newUser); + doReturn(newUser).when(mUserManager).createUser(mTestUserName, UserInfo.FLAG_ADMIN); + assertThat(mCarUserManagerHelper.createNewAdminUser(mTestUserName)).isEqualTo(newUser); } @Test @@ -243,11 +252,11 @@ public class CarUserManagerHelperTest { String newAdminName = "Test new admin"; UserInfo expectedAdmin = new UserInfo(); expectedAdmin.name = newAdminName; - when(mUserManager.createUser(newAdminName, UserInfo.FLAG_ADMIN)).thenReturn(expectedAdmin); + doReturn(expectedAdmin).when(mUserManager).createUser(newAdminName, UserInfo.FLAG_ADMIN); // Admins can create other admins. - when(mUserManager.isAdminUser()).thenReturn(true); - UserInfo actualAdmin = mHelper.createNewAdminUser(newAdminName); + doReturn(true).when(mUserManager).isAdminUser(); + UserInfo actualAdmin = mCarUserManagerHelper.createNewAdminUser(newAdminName); assertThat(actualAdmin).isEqualTo(expectedAdmin); } @@ -256,11 +265,11 @@ public class CarUserManagerHelperTest { String newAdminName = "Test new admin"; UserInfo expectedAdmin = new UserInfo(); expectedAdmin.name = newAdminName; - when(mUserManager.createUser(newAdminName, UserInfo.FLAG_ADMIN)).thenReturn(expectedAdmin); + doReturn(expectedAdmin).when(mUserManager).createUser(newAdminName, UserInfo.FLAG_ADMIN); // Test that non-admins cannot create new admins. - when(mUserManager.isAdminUser()).thenReturn(false); // Current user non-admin. - assertThat(mHelper.createNewAdminUser(newAdminName)).isNull(); + doReturn(false).when(mUserManager).isAdminUser(); // Current user non-admin. + assertThat(mCarUserManagerHelper.createNewAdminUser(newAdminName)).isNull(); } @Test @@ -268,82 +277,99 @@ public class CarUserManagerHelperTest { String newAdminName = "Test new admin"; UserInfo expectedAdmin = new UserInfo(); expectedAdmin.name = newAdminName; - when(mUserManager.createUser(newAdminName, UserInfo.FLAG_ADMIN)).thenReturn(expectedAdmin); + + doReturn(expectedAdmin).when(mUserManager).createUser(newAdminName, UserInfo.FLAG_ADMIN); // System user can create admins. - when(mUserManager.isSystemUser()).thenReturn(true); - UserInfo actualAdmin = mHelper.createNewAdminUser(newAdminName); + doReturn(true).when(mUserManager).isSystemUser(); + UserInfo actualAdmin = mCarUserManagerHelper.createNewAdminUser(newAdminName); assertThat(actualAdmin).isEqualTo(expectedAdmin); } @Test public void testCreateNewNonAdminUser() { // Verify createUser on UserManager gets called. - mHelper.createNewNonAdminUser(mTestUserName); + mCarUserManagerHelper.createNewNonAdminUser(mTestUserName); verify(mUserManager).createUser(mTestUserName, 0); - when(mUserManager.createUser(mTestUserName, 0)).thenReturn(null); - assertThat(mHelper.createNewNonAdminUser(mTestUserName)).isNull(); + doReturn(null).when(mUserManager).createUser(mTestUserName, 0); + assertThat(mCarUserManagerHelper.createNewNonAdminUser(mTestUserName)).isNull(); UserInfo newUser = new UserInfo(); newUser.name = mTestUserName; - when(mUserManager.createUser(mTestUserName, 0)).thenReturn(newUser); - assertThat(mHelper.createNewNonAdminUser(mTestUserName)).isEqualTo(newUser); + doReturn(newUser).when(mUserManager).createUser(mTestUserName, 0); + assertThat(mCarUserManagerHelper.createNewNonAdminUser(mTestUserName)).isEqualTo(newUser); } @Test public void testCannotRemoveSystemUser() { - assertThat(mHelper.removeUser(mSystemUser, mGuestUserName)).isFalse(); + assertThat(mCarUserManagerHelper.removeUser(mSystemUser, mGuestUserName)).isFalse(); } @Test public void testAdminsCanRemoveOtherUsers() { int idToRemove = mCurrentProcessUser.id + 2; UserInfo userToRemove = createUserInfoForId(idToRemove); - when(mUserManager.removeUser(idToRemove)).thenReturn(true); + + doReturn(true).when(mUserManager).removeUser(idToRemove); // If Admin is removing non-current, non-system user, simply calls removeUser. - when(mUserManager.isAdminUser()).thenReturn(true); - assertThat(mHelper.removeUser(userToRemove, mGuestUserName)).isTrue(); + doReturn(true).when(mUserManager).isAdminUser(); + assertThat(mCarUserManagerHelper.removeUser(userToRemove, mGuestUserName)).isTrue(); verify(mUserManager).removeUser(idToRemove); } @Test - public void testNonAdminsCanOnlyRemoveThemselves() { + public void testNonAdminsCanNotRemoveOtherUsers() { UserInfo otherUser = createUserInfoForId(mCurrentProcessUser.id + 2); // Make current user non-admin. - when(mUserManager.isAdminUser()).thenReturn(false); + doReturn(false).when(mUserManager).isAdminUser(); // Mock so that removeUser always pretends it's successful. - when(mUserManager.removeUser(anyInt())).thenReturn(true); + doReturn(true).when(mUserManager).removeUser(anyInt()); // If Non-Admin is trying to remove someone other than themselves, they should fail. - assertThat(mHelper.removeUser(otherUser, mGuestUserName)).isFalse(); + assertThat(mCarUserManagerHelper.removeUser(otherUser, mGuestUserName)).isFalse(); verify(mUserManager, never()).removeUser(otherUser.id); } @Test + public void testRemoveLastActiveUser() { + // Cannot remove system user. + assertThat(mCarUserManagerHelper.removeUser(mSystemUser, mGuestUserName)).isFalse(); + + UserInfo adminInfo = new UserInfo(/* id= */10, "admin", UserInfo.FLAG_ADMIN); + List<UserInfo> users = new ArrayList<UserInfo>(); + users.add(adminInfo); + + doReturn(users).when(mUserManager).getUsers(true); + + assertThat(mCarUserManagerHelper.removeUser(adminInfo, mGuestUserName)) + .isEqualTo(false); + } + + @Test public void testSwitchToGuest() { - mHelper.startNewGuestSession(mGuestUserName); + mCarUserManagerHelper.startNewGuestSession(mGuestUserName); verify(mUserManager).createGuest(mContext, mGuestUserName); - UserInfo guestInfo = new UserInfo(21, mGuestUserName, UserInfo.FLAG_GUEST); - when(mUserManager.createGuest(mContext, mGuestUserName)).thenReturn(guestInfo); - mHelper.startNewGuestSession(mGuestUserName); + UserInfo guestInfo = new UserInfo(/* id= */21, mGuestUserName, UserInfo.FLAG_GUEST); + doReturn(guestInfo).when(mUserManager).createGuest(mContext, mGuestUserName); + mCarUserManagerHelper.startNewGuestSession(mGuestUserName); verify(mActivityManager).switchUser(21); } @Test public void testGetUserIcon() { - mHelper.getUserIcon(mCurrentProcessUser); + mCarUserManagerHelper.getUserIcon(mCurrentProcessUser); verify(mUserManager).getUserIcon(mCurrentProcessUser.id); } @Test public void testScaleUserIcon() { Bitmap fakeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); - Drawable scaledIcon = mHelper.scaleUserIcon(fakeIcon, 300); + Drawable scaledIcon = mCarUserManagerHelper.scaleUserIcon(fakeIcon, 300); assertThat(scaledIcon.getIntrinsicWidth()).isEqualTo(300); assertThat(scaledIcon.getIntrinsicHeight()).isEqualTo(300); } @@ -352,17 +378,17 @@ public class CarUserManagerHelperTest { public void testSetUserName() { UserInfo testInfo = createUserInfoForId(mCurrentProcessUser.id + 3); String newName = "New Test Name"; - mHelper.setUserName(testInfo, newName); + mCarUserManagerHelper.setUserName(testInfo, newName); verify(mUserManager).setUserName(mCurrentProcessUser.id + 3, newName); } @Test public void testIsCurrentProcessSystemUser() { - when(mUserManager.isAdminUser()).thenReturn(true); - assertThat(mHelper.isCurrentProcessAdminUser()).isTrue(); + doReturn(true).when(mUserManager).isAdminUser(); + assertThat(mCarUserManagerHelper.isCurrentProcessAdminUser()).isTrue(); - when(mUserManager.isAdminUser()).thenReturn(false); - assertThat(mHelper.isCurrentProcessAdminUser()).isFalse(); + doReturn(false).when(mUserManager).isAdminUser(); + assertThat(mCarUserManagerHelper.isCurrentProcessAdminUser()).isFalse(); } @Test @@ -371,13 +397,13 @@ public class CarUserManagerHelperTest { UserInfo testInfo = createUserInfoForId(userId); // Test that non-admins cannot assign admin privileges. - when(mUserManager.isAdminUser()).thenReturn(false); // Current user non-admin. - mHelper.assignAdminPrivileges(testInfo); + doReturn(false).when(mUserManager).isAdminUser(); // Current user non-admin. + mCarUserManagerHelper.assignAdminPrivileges(testInfo); verify(mUserManager, never()).setUserAdmin(userId); // Admins can assign admin privileges. - when(mUserManager.isAdminUser()).thenReturn(true); - mHelper.assignAdminPrivileges(testInfo); + doReturn(true).when(mUserManager).isAdminUser(); + mCarUserManagerHelper.assignAdminPrivileges(testInfo); verify(mUserManager).setUserAdmin(userId); } @@ -386,11 +412,13 @@ public class CarUserManagerHelperTest { int userId = 20; UserInfo testInfo = createUserInfoForId(userId); - mHelper.setUserRestriction(testInfo, UserManager.DISALLOW_ADD_USER, /* enable= */ true); + mCarUserManagerHelper.setUserRestriction( + testInfo, UserManager.DISALLOW_ADD_USER, /* enable= */ true); verify(mUserManager).setUserRestriction( UserManager.DISALLOW_ADD_USER, true, UserHandle.of(userId)); - mHelper.setUserRestriction(testInfo, UserManager.DISALLOW_REMOVE_USER, /* enable= */ false); + mCarUserManagerHelper.setUserRestriction( + testInfo, UserManager.DISALLOW_REMOVE_USER, /* enable= */ false); verify(mUserManager).setUserRestriction( UserManager.DISALLOW_REMOVE_USER, false, UserHandle.of(userId)); } @@ -400,9 +428,10 @@ public class CarUserManagerHelperTest { String testUserName = "Test User"; int userId = 20; UserInfo newNonAdmin = createUserInfoForId(userId); - when(mUserManager.createUser(testUserName, /* flags= */ 0)).thenReturn(newNonAdmin); - mHelper.createNewNonAdminUser(testUserName); + doReturn(newNonAdmin).when(mUserManager).createUser(testUserName, /* flags= */ 0); + + mCarUserManagerHelper.createNewNonAdminUser(testUserName); verify(mUserManager).setUserRestriction( UserManager.DISALLOW_FACTORY_RESET, /* enable= */ true, UserHandle.of(userId)); @@ -417,9 +446,11 @@ public class CarUserManagerHelperTest { int testUserId = 30; boolean restrictionEnabled = false; UserInfo testInfo = createUserInfoForId(testUserId); - when(mUserManager.isAdminUser()).thenReturn(true); // Only admins can assign privileges. - mHelper.assignAdminPrivileges(testInfo); + // Only admins can assign privileges. + doReturn(true).when(mUserManager).isAdminUser(); + + mCarUserManagerHelper.assignAdminPrivileges(testInfo); verify(mUserManager).setUserRestriction( UserManager.DISALLOW_FACTORY_RESET, restrictionEnabled, UserHandle.of(testUserId)); @@ -427,7 +458,7 @@ public class CarUserManagerHelperTest { @Test public void testRegisterUserChangeReceiver() { - mHelper.registerOnUsersUpdateListener(mTestListener); + mCarUserManagerHelper.registerOnUsersUpdateListener(mTestListener); ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); @@ -465,10 +496,52 @@ public class CarUserManagerHelperTest { assertThat(handlerCaptor.getValue()).isNull(); // Unregister the receiver. - mHelper.unregisterOnUsersUpdateListener(); + mCarUserManagerHelper.unregisterOnUsersUpdateListener(); verify(mContext).unregisterReceiver(receiverCaptor.getValue()); } + @Test + public void testGetInitialUserWithValidLastActiveUser() { + SystemProperties.set("android.car.systemuser.headless", "true"); + int lastActiveUserId = 12; + + UserInfo otherUser1 = createUserInfoForId(lastActiveUserId - 2); + UserInfo otherUser2 = createUserInfoForId(lastActiveUserId - 1); + UserInfo otherUser3 = createUserInfoForId(lastActiveUserId); + + List<UserInfo> testUsers = new ArrayList<>(); + testUsers.add(mSystemUser); + testUsers.add(otherUser1); + testUsers.add(otherUser2); + testUsers.add(otherUser3); + + mCarUserManagerHelper.setLastActiveUser( + lastActiveUserId, /* skipGlobalSettings= */ true); + doReturn(testUsers).when(mUserManager).getUsers(true); + + assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(lastActiveUserId); + } + + @Test + public void testGetInitialUserWithNonExistLastActiveUser() { + SystemProperties.set("android.car.systemuser.headless", "true"); + int lastActiveUserId = 12; + + UserInfo otherUser1 = createUserInfoForId(lastActiveUserId - 2); + UserInfo otherUser2 = createUserInfoForId(lastActiveUserId - 1); + + List<UserInfo> testUsers = new ArrayList<>(); + testUsers.add(mSystemUser); + testUsers.add(otherUser1); + testUsers.add(otherUser2); + + mCarUserManagerHelper.setLastActiveUser( + lastActiveUserId, /* skipGlobalSettings= */ true); + doReturn(testUsers).when(mUserManager).getUsers(true); + + assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(lastActiveUserId - 2); + } + private UserInfo createUserInfoForId(int id) { UserInfo userInfo = new UserInfo(); userInfo.id = id; diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java index 20cb060f28..a6b48bf8f1 100644 --- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java +++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java @@ -84,9 +84,10 @@ public class CarUserServiceTest { mCarUserService.init(); verify(mMockContext).registerReceiver(eq(mCarUserService), argument.capture()); IntentFilter intentFilter = argument.getValue(); - assertThat(intentFilter.countActions()).isEqualTo(1); + assertThat(intentFilter.countActions()).isEqualTo(2); assertThat(intentFilter.getAction(0)).isEqualTo(Intent.ACTION_LOCKED_BOOT_COMPLETED); + assertThat(intentFilter.getAction(1)).isEqualTo(Intent.ACTION_USER_SWITCHED); } /** @@ -139,4 +140,47 @@ public class CarUserServiceTest { verify(mCarUserManagerHelper). setUserRestriction(user0, UserManager.DISALLOW_MODIFY_ACCOUNTS, true); } + + /** + * Test that the {@link CarUserService} starts up the last active user on reboot. + */ + @Test + public void testStartsLastActiveUserOnReboot() { + List<UserInfo> users = new ArrayList<>(); + + int adminUserId = 10; + UserInfo admin = new UserInfo(adminUserId, CarUserService.OWNER_NAME, UserInfo.FLAG_ADMIN); + + int secUserId = 11; + UserInfo secUser = + new UserInfo(secUserId, CarUserService.OWNER_NAME, UserInfo.FLAG_ADMIN); + + users.add(admin); + users.add(secUser); + + doReturn(users).when(mCarUserManagerHelper).getAllUsers(); + doReturn(secUserId).when(mCarUserManagerHelper).getLastActiveUser(); + + mCarUserService.onReceive(mMockContext, + new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)); + + verify(mCarUserManagerHelper).switchToUserId(secUserId); + } + + /** + * Test that the {@link CarUserService} updates last active user on user switch intent. + */ + @Test + public void testLastActiveUserUpdatedOnUserSwitch() { + int lastActiveUserId = 11; + + doReturn(false).when(mCarUserManagerHelper).isForegroundUserGuest(); + doReturn(lastActiveUserId).when(mCarUserManagerHelper).getCurrentForegroundUserId(); + + mCarUserService.onReceive(mMockContext, + new Intent(Intent.ACTION_USER_SWITCHED)); + + verify(mCarUserManagerHelper).setLastActiveUser( + lastActiveUserId, /* skipGlobalSetting= */ false); + } } |