diff options
author | 2025-03-12 14:04:51 +0000 | |
---|---|---|
committer | 2025-03-13 17:24:14 +0000 | |
commit | 001b7bd2fae2078b6a6cd490958d495508a6d881 (patch) | |
tree | b6b23d047db33901d7403642142aab38d52216bb | |
parent | 79a1f4c6d841739e30e0c339c52be39dc42af086 (diff) |
Handle x-profile delegation for java picker.
Bug: b/402367358
Test: atest MediaProviderTests:UserManagerStateTest
Flag: EXEMPT bug_fix
Change-Id: Iabc4de0d39720dcb355cf98c99724feacf6899e0
-rw-r--r-- | src/com/android/providers/media/photopicker/data/UserManagerState.java | 330 | ||||
-rw-r--r-- | tests/src/com/android/providers/media/photopicker/data/UserManagerStateTest.java | 245 |
2 files changed, 297 insertions, 278 deletions
diff --git a/src/com/android/providers/media/photopicker/data/UserManagerState.java b/src/com/android/providers/media/photopicker/data/UserManagerState.java index 74c06e872..8df364c3c 100644 --- a/src/com/android/providers/media/photopicker/data/UserManagerState.java +++ b/src/com/android/providers/media/photopicker/data/UserManagerState.java @@ -21,8 +21,6 @@ import static androidx.core.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresApi; -import android.annotation.SuppressLint; -import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -242,48 +240,40 @@ public interface UserManagerState { setUserIds(); } - private UserId getSystemUser() { - return UserId.of(UserHandle.of(ActivityManager.getCurrentUser())); - } - private void setUserIds() { - setUserIdsInternal(); - mIsMultiUserProfiles.postValue(isMultiUserProfiles()); - } - - private void setUserIdsInternal() { mUserProfileIds.clear(); - mUserProfileIds.add(getSystemUser()); - if (mUserManager == null) { - Log.e(TAG, "Cannot obtain user manager"); - return; - } - // Here there could be other profiles too , that we do not want to show anywhere - // in photo picker at all. - final List<UserHandle> userProfiles = mUserManager.getUserProfiles(); - if (SdkLevel.isAtLeastV()) { - for (UserHandle userHandle : userProfiles) { - UserProperties userProperties = mUserManager.getUserProperties(userHandle); - UserId userId = UserId.of(userHandle); - - // Check if we want to show this profile data in PhotoPicker or if it is - // an owner profile itself. - if (getSystemUser().getIdentifier() != userHandle.getIdentifier() - && userProperties.getShowInSharingSurfaces() - == userProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) { - mUserProfileIds.add(userId); + mUserProfileIds.add(mCurrentUser); + boolean currentUserIsManaged = + mUserManager.isManagedProfile(mCurrentUser.getIdentifier()); + + for (UserHandle handle : mUserManager.getUserProfiles()) { + + // For >= Android V, check if the profile wants to be shown + if (SdkLevel.isAtLeastV()) { + + UserProperties properties = mUserManager.getUserProperties(handle); + if (properties.getShowInSharingSurfaces() + != UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) { + continue; } - } - } else { - // if sdk version is less than V, then maximum two profiles with separate tab - // could only be available - for (UserHandle userHandle : userProfiles) { - if (mUserManager.isManagedProfile(userHandle.getIdentifier())) { - mUserProfileIds.add(UserId.of(userHandle)); + } else { + // Only allow managed profiles + the parent user on lower than V. + if (currentUserIsManaged + && mUserManager.getProfileParent(mCurrentUser.getUserHandle()) + == handle) { + // Intentionally empty so that this profile gets added. + } else if (!mUserManager.isManagedProfile(handle.getIdentifier())) { + continue; } } + + // Ensure the system user doesn't get added twice. + if (mUserProfileIds.contains(UserId.of(handle))) continue; + mUserProfileIds.add(UserId.of(handle)); } + + mIsMultiUserProfiles.postValue(isMultiUserProfiles()); } @Override @@ -312,12 +302,162 @@ public interface UserManagerState { return crossProfileAllowedStatusForAll; } + + /** + * External method that allows quick checking from the current user to a target user. + * + * Takes into account the On/Off state of the profile, as well as cross profile content + * sharing policies. + * + * @param targetUser the target of the access. Current User is the "from" user. + * @return If the target user currently is eligible for cross profile content sharing. + */ @Override - public boolean isCrossProfileAllowedToUser(UserId otherUser) { + public boolean isCrossProfileAllowedToUser(UserId targetUser) { assertMainThread(); - return !isProfileOff(otherUser) && !isBlockedByAdmin(otherUser); + return !isProfileOff(targetUser) && !isBlockedByAdmin(targetUser); } + /** + * Determines if the provided UserIds support CrossProfile content sharing. + * + * <p>This method accepts a pair of user handles (from/to) and determines if CrossProfile + * access is permitted between those two profiles. + * + * <p>There are differences is on how the access is determined based on the platform SDK: + * + * <p>For Platform SDK < V: + * + * <p>A check for CrossProfileIntentForwarders in the origin (from) profile that target the + * destination (to) profile. If such a forwarder exists, then access is allowed, and denied + * otherwise. + * + * <p>For Platform SDK >= V: + * + * <p>The method now takes into account access delegation, which was first added in Android + * V. + * + * <p>For profiles that set the [CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT] + * property in its [UserProperties], its parent profile will be substituted in for its side + * of the check. + * + * <p>ex. For access checks between a Managed (from) and Private (to) profile, where: - + * Managed does not delegate to its parent - Private delegates to its parent + * + * <p>The following logic is performed: Managed -> parent(Private) + * + * <p>The same check in the other direction would yield: parent(Private) -> Managed + * + * <p>Note how the private profile is never actually used for either side of the check, + * since it is delegating its access check to the parent. And thus, if Managed can access + * the parent, it can also access the private. + * + * @param context Current context object, for switching user contexts. + * @param intent The current intent the Photopicker is running under. + * @param fromUser The Origin profile, where the user is coming from + * @param toUser The destination profile, where the user is attempting to go to. + * @return Whether CrossProfile content sharing is supported in this handle. + */ + private boolean isCrossProfileAllowedToUser( + Context context, Intent intent, UserId fromUser, UserId toUser) { + + // Early exit conditions, accessing self. + // NOTE: It is also possible to reach this state if this method is recursively checking + // from: parent(A) to:parent(B) where A and B are both children of the same parent. + if (fromUser.getIdentifier() == toUser.getIdentifier()) { + return true; + } + + // Decide if we should use actual from or parent(from) + UserHandle currentFromUser = + getProfileToCheckCrossProfileAccess(fromUser.getUserHandle()); + + // Decide if we should use actual to or parent(to) + UserHandle currentToUser = getProfileToCheckCrossProfileAccess(toUser.getUserHandle()); + + // When the from/to has changed from the original parameters, recursively restart the + // checks with the new from/to handles. + if (fromUser.getIdentifier() != currentFromUser.getIdentifier() + || toUser.getIdentifier() != currentToUser.getIdentifier()) { + return isCrossProfileAllowedToUser( + context, intent, UserId.of(currentFromUser), UserId.of(currentToUser)); + } + + return doesCrossProfileIntentForwarderExist( + intent, + mContext.getPackageManager(), + fromUser.getUserHandle(), + toUser.getUserHandle()); + } + + /** + * Checks the Intent to see if it can be resolved as a CrossProfileIntentForwarderActivity + * for the target user. + * + * @param intent The current intent the photopicker is running under. + * @param pm the PM which will be used for querying. + * @param fromUser the [UserHandle] of the origin user + * @param targetUserHandle the [UserHandle] of the target user + * @return Whether the current Intent Photopicker may be running under has a matching + * CrossProfileIntentForwarderActivity + */ + private boolean doesCrossProfileIntentForwarderExist( + Intent intent, + PackageManager pm, + UserHandle fromUser, + UserHandle targetUserHandle) { + + // Clear out the component & package before attempting to match + Intent intentToCheck = (Intent) intent.clone(); + intentToCheck.setComponent(null); + intentToCheck.setPackage(null); + + for (ResolveInfo resolveInfo : + pm.queryIntentActivitiesAsUser( + intentToCheck, PackageManager.MATCH_DEFAULT_ONLY, fromUser)) { + + // If the activity is a CrossProfileIntentForwardingActivity, inspect its + // targetUserId to see if it targets the user we are currently checking for. + if (resolveInfo.isCrossProfileIntentForwarderActivity()) { + + /* + * IMPORTANT: This is a reflection based hack to ensure the profile is + * actually the installer of the CrossProfileIntentForwardingActivity. + * + * ResolveInfo.targetUserId exists, but is a hidden API not available to + * mainline modules, and no such API exists, so it is accessed via + * reflection below. All exceptions are caught to protect against + * reflection related issues such as: + * NoSuchFieldException / IllegalAccessException / SecurityException. + * + * In the event of an exception, the code fails "closed" for the current + * profile to avoid showing content that should not be visible. + */ + try { + Field targetUserIdField = + resolveInfo.getClass().getDeclaredField("targetUserId"); + targetUserIdField.setAccessible(true); + int targetUserId = (int) targetUserIdField.get(resolveInfo); + + if (targetUserId == targetUserHandle.getIdentifier()) { + // Don't need to look further, exit the loop. + return true; + } + + } catch (NoSuchFieldException | IllegalAccessException | SecurityException ex) { + // Couldn't check the targetUserId via reflection, so fail without + // further iterations. + Log.e(TAG, "Could not access targetUserId via reflection.", ex); + return false; + } catch (Exception ex) { + Log.e(TAG, "Exception occurred during cross profile checks", ex); + } + } + } + return false; + } + + @Override public MutableLiveData<Boolean> getIsMultiUserProfiles() { return mIsMultiUserProfiles; @@ -331,8 +471,7 @@ public interface UserManagerState { @Override public void resetUserIdsAndSetCrossProfileValues(Intent intent) { - assertMainThread(); - setUserIdsInternal(); + resetUserIds(); setCrossProfileValues(intent); mIsMultiUserProfiles.postValue(isMultiUserProfiles()); } @@ -510,6 +649,12 @@ public interface UserManagerState { || !CrossProfileUtils.isMediaProviderAvailable(userId, mContext); } + /** + * Determines if the target UserHandle delegates its content sharing to its parent. + * + * @param userHandle The target handle to check delegation for. + * @return TRUE if V+ and the handle delegates to parent. False otherwise. + */ private boolean isCrossProfileStrategyDelegatedToParent(UserHandle userHandle) { if (SdkLevel.isAtLeastV()) { if (mUserManager == null) { @@ -525,6 +670,15 @@ public interface UserManagerState { return false; } + /** + * Acquires the correct {@link UserHandle} which should be used for CrossProfile access + * checks. + * + * @param userHandle the origin handle. + * @return The UserHandle that should be used for cross profile access checks. In the event + * the origin handle delegates its access, this may not be the same handle as the origin + * handle. + */ private UserHandle getProfileToCheckCrossProfileAccess(UserHandle userHandle) { if (mUserManager == null) { Log.e(TAG, "Cannot obtain user manager"); @@ -551,7 +705,6 @@ public interface UserManagerState { * @param intent The intent Photopicker is currently running under, for * CrossProfileForwardActivity checking. */ - @SuppressLint("DiscouragedPrivateApi") private void setBlockedByAdminValue(Intent intent) { if (intent == null) { Log.e( @@ -561,95 +714,6 @@ public interface UserManagerState { return; } - Map<UserId, Boolean> profileIsAccessibleToProcessOwner = new HashMap<>(); - List<UserId> delegatedFromParent = new ArrayList<>(); - - final PackageManager pm = mContext.getPackageManager(); - - // Resolve CrossProfile activities for all user profiles that Photopicker is - // aware of. - for (UserId userId : mUserProfileIds) { - - // If the UserId is the system user, exit early. - if (userId.getIdentifier() == mCurrentUser.getIdentifier()) { - profileIsAccessibleToProcessOwner.put(userId, true); - continue; - } - - // This UserId delegates its strategy to the parent profile - if (isCrossProfileStrategyDelegatedToParent(userId.getUserHandle())) { - delegatedFromParent.add(userId); - continue; - } - - // Clear out the component & package before attempting to match - Intent intentToCheck = (Intent) intent.clone(); - intentToCheck.setComponent(null); - intentToCheck.setPackage(null); - - for (ResolveInfo resolveInfo : - pm.queryIntentActivities( - intentToCheck, PackageManager.MATCH_DEFAULT_ONLY)) { - - // If the activity is a CrossProfileIntentForwardingActivity, inspect its - // targetUserId to - // see if it targets the user we are currently checking for. - if (resolveInfo.isCrossProfileIntentForwarderActivity()) { - - /* - * IMPORTANT: This is a reflection based hack to ensure the profile is - * actually the installer of the CrossProfileIntentForwardingActivity. - * - * ResolveInfo.targetUserId exists, but is a hidden API not available to - * mainline modules, and no such API exists, so it is accessed via - * reflection below. All exceptions are caught to protect against - * reflection related issues such as: - * NoSuchFieldException / IllegalAccessException / SecurityException. - * - * In the event of an exception, the code fails "closed" for the current - * profile to avoid showing content that should not be visible. - */ - try { - Field targetUserIdField = - resolveInfo.getClass().getDeclaredField("targetUserId"); - targetUserIdField.setAccessible(true); - int targetUserId = (int) targetUserIdField.get(resolveInfo); - - if (targetUserId == userId.getIdentifier()) { - profileIsAccessibleToProcessOwner.put(userId, true); - - // Don't need to look further, exit the loop. - break; - } - - } catch (NoSuchFieldException - | IllegalAccessException - | SecurityException ex) { - // Couldn't check the targetUserId via reflection, so fail without - // further - // iterations. - Log.e(TAG, "Could not access targetUserId via reflection.", ex); - break; - } catch (Exception ex) { - Log.e(TAG, "Exception occurred during cross profile checks", ex); - } - } - } - // Fail case, was unable to find a suitable Activity for this user. - profileIsAccessibleToProcessOwner.putIfAbsent(userId, false); - } - - // For profiles that delegate their access to the parent, set the access for - // those profiles equal to the same as their parent. - for (UserId userId : delegatedFromParent) { - UserHandle parent = - mUserManager.getProfileParent(UserHandle.of(userId.getIdentifier())); - profileIsAccessibleToProcessOwner.put( - userId, - profileIsAccessibleToProcessOwner.getOrDefault( - UserId.of(parent), /* default= */ false)); - } - mIsProfileBlockedByAdminMap.clear(); for (UserId userId : mUserProfileIds) { mIsProfileBlockedByAdminMap.put( @@ -657,8 +721,8 @@ public interface UserManagerState { // calculated, (which are blocked, rather than which are accessible) so the // boolean needs to be inverted. userId, - !profileIsAccessibleToProcessOwner.getOrDefault( - userId, /* default= */ false)); + !isCrossProfileAllowedToUser(mContext, intent, UserId.CURRENT_USER, userId) + ); } } diff --git a/tests/src/com/android/providers/media/photopicker/data/UserManagerStateTest.java b/tests/src/com/android/providers/media/photopicker/data/UserManagerStateTest.java index dda66c673..f2fc38d9d 100644 --- a/tests/src/com/android/providers/media/photopicker/data/UserManagerStateTest.java +++ b/tests/src/com/android/providers/media/photopicker/data/UserManagerStateTest.java @@ -23,6 +23,7 @@ import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -111,6 +112,7 @@ public class UserManagerStateTest { // set Managed Profile identification when(mMockUserManager.isManagedProfile(mManagedUser.getIdentifier())).thenReturn(true); + when(mMockUserManager.isManagedProfile(mManagedUser2.getIdentifier())).thenReturn(true); when(mMockUserManager.isManagedProfile(mPersonalUser.getIdentifier())).thenReturn(false); when(mMockUserManager.isManagedProfile(mOtherUser1.getIdentifier())).thenReturn(false); when(mMockUserManager.isManagedProfile(mOtherUser2.getIdentifier())).thenReturn(false); @@ -171,6 +173,62 @@ public class UserManagerStateTest { } @Test + public void testCrossProfileAccessWithDelegationVPlus() { + assumeTrue(SdkLevel.isAtLeastV()); + + // Return a ResolveInfo for the correct managed profile. + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), any(UserHandle.class))) + .thenReturn(List.of()); + + initializeUserManagerState( + UserId.of(mPersonalUser), + Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1)); + + InstrumentationRegistry.getInstrumentation() + .runOnMainSync( + () -> { + mUserManagerState.setIntentAndCheckRestrictions(new Intent()); + assertThat( + mUserManagerState.isCrossProfileAllowedToUser( + UserId.of(mManagedUser))) + .isFalse(); + assertThat( + mUserManagerState.isCrossProfileAllowedToUser( + UserId.of(mOtherUser1))) + .isTrue(); + }); + } + + @Test + public void testCrossProfileAccessWithDelegationManagedToPrivateVPlus() { + assumeTrue(SdkLevel.isAtLeastV()); + + // Return a ResolveInfo for the personal profile only. + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mManagedUser))) + .thenReturn(List.of(new ReflectedResolveInfo(mPersonalUser.getIdentifier()))); + + initializeUserManagerState( + UserId.of(mManagedUser), + Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1)); + + InstrumentationRegistry.getInstrumentation() + .runOnMainSync( + () -> { + mUserManagerState.setIntentAndCheckRestrictions(new Intent()); + assertThat( + mUserManagerState.isCrossProfileAllowedToUser( + UserId.of(mPersonalUser))) + .isTrue(); + assertThat( + mUserManagerState.isCrossProfileAllowedToUser( + UserId.of(mOtherUser1))) + .isTrue(); + }); + } + + @Test public void testCrossProfileAccessWithMultipleManagedProfilesIsAllowedVPlus() { assumeTrue(SdkLevel.isAtLeastV()); @@ -186,7 +244,8 @@ public class UserManagerStateTest { when(mMockUserManager.getUserProperties(mManagedUser2)).thenReturn(mManagedUser2Properties); // Return a ResolveInfo for the correct managed profile. - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mPersonalUser))) .thenReturn(List.of(new ReflectedResolveInfo(mManagedUser2.getIdentifier()))); initializeUserManagerState( @@ -224,7 +283,8 @@ public class UserManagerStateTest { when(mMockUserManager.getUserProperties(mManagedUser2)).thenReturn(mManagedUser2Properties); // Return a ResolveInfo for the OTHER managed profile. - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mPersonalUser))) .thenReturn(List.of(new ReflectedResolveInfo(mManagedUser.getIdentifier()))); initializeUserManagerState( @@ -254,7 +314,8 @@ public class UserManagerStateTest { when(mMockUserManager.isManagedProfile(mManagedUser2.getIdentifier())).thenReturn(true); // Return a ResolveInfo for the correct managed profile. - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mPersonalUser))) .thenReturn(List.of(new ReflectedResolveInfo(mManagedUser2.getIdentifier()))); initializeUserManagerState( @@ -280,7 +341,8 @@ public class UserManagerStateTest { when(mMockUserManager.isManagedProfile(mManagedUser2.getIdentifier())).thenReturn(true); // Return a ResolveInfo for the OTHER managed profile. - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mPersonalUser))) .thenReturn(List.of(new ReflectedResolveInfo(mManagedUser.getIdentifier()))); initializeUserManagerState( @@ -349,19 +411,14 @@ public class UserManagerStateTest { public void testGetAllUserProfileIdsThatNeedToShowInPhotoPicker_currentUserIsPersonalUser() { initializeUserManagerState( UserId.of(mPersonalUser), - Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1, mOtherUser2)); + Arrays.asList(mPersonalUser, mManagedUser)); InstrumentationRegistry.getInstrumentation() .runOnMainSync( () -> { List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser), - UserId.of(mOtherUser1)) - : Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser)); + Arrays.asList( + UserId.of(mPersonalUser), + UserId.of(mManagedUser)); assertThat(mUserManagerState.getAllUserProfileIds()) .containsExactlyElementsIn(userIdList); @@ -372,19 +429,14 @@ public class UserManagerStateTest { public void testGetAllUserProfileIdsThatNeedToShowInPhotoPicker_currentUserIsManagedUser() { initializeUserManagerState( UserId.of(mManagedUser), - Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1, mOtherUser2)); + Arrays.asList(mPersonalUser, mManagedUser)); InstrumentationRegistry.getInstrumentation() .runOnMainSync( () -> { List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser), - UserId.of(mOtherUser1)) - : Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser)); + Arrays.asList( + UserId.of(mPersonalUser), + UserId.of(mManagedUser)); assertThat(mUserManagerState.getAllUserProfileIds()) .containsExactlyElementsIn(userIdList); @@ -392,22 +444,21 @@ public class UserManagerStateTest { } @Test - public void testGetAllUserProfileIdsThatNeedToShowInPhotoPicker_currentUserIsOtherUser1() { + public void + testGetAllUserProfileIdsThatNeedToShowInPhotoPicker_currentUserIsOtherUser1VPlus() { + assumeTrue(SdkLevel.isAtLeastV()); initializeUserManagerState( UserId.of(mOtherUser1), - Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1, mOtherUser2)); + Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1)); InstrumentationRegistry.getInstrumentation() .runOnMainSync( () -> { List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser), - UserId.of(mOtherUser1)) - : Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser)); + Arrays.asList( + UserId.of(mPersonalUser), + UserId.of(mManagedUser), + UserId.of(mOtherUser1)); + assertThat(mUserManagerState.getAllUserProfileIds()) .containsExactlyElementsIn(userIdList); }); @@ -433,6 +484,7 @@ public class UserManagerStateTest { @Test public void testUserIds_multiUserProfilesAvailable_currentUserIsPersonalUser() { + assumeFalse(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mPersonalUser); // if available user profiles are {personal , managed, otherUser1 } @@ -446,13 +498,7 @@ public class UserManagerStateTest { assertThat(mUserManagerState.getCurrentUserProfileId()) .isEqualTo(UserId.of(mPersonalUser)); - List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser), - UserId.of(mOtherUser1)) - : Arrays.asList( + List<UserId> userIdList = Arrays.asList( UserId.of(mPersonalUser), UserId.of(mManagedUser)); assertThat(mUserManagerState.getAllUserProfileIds()) @@ -463,77 +509,36 @@ public class UserManagerStateTest { mUserManagerState.getCurrentUserProfileId())) .isFalse(); }); - - // if available user profiles are {personal , otherUser1 } - initializeUserManagerState(currentUser, Arrays.asList(mPersonalUser, mOtherUser1)); - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - if (SdkLevel.isAtLeastV()) { - assertThat(mUserManagerState.isMultiUserProfiles()).isTrue(); - } else { - assertThat(mUserManagerState.isMultiUserProfiles()).isFalse(); - } - - List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mOtherUser1)) - : Arrays.asList(UserId.of(mPersonalUser)); - assertThat(mUserManagerState.getAllUserProfileIds()) - .containsExactlyElementsIn(userIdList); - }); - - // if available user profiles are {personal , otherUser2 } - initializeUserManagerState(currentUser, Arrays.asList(mPersonalUser, mOtherUser2)); - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - assertThat(mUserManagerState.isMultiUserProfiles()).isFalse(); - - assertThat(mUserManagerState.getCurrentUserProfileId()) - .isEqualTo(UserId.of(mPersonalUser)); - assertThat(mUserManagerState.getAllUserProfileIds()) - .containsExactlyElementsIn( - Arrays.asList(UserId.of(mPersonalUser))); - }); } @Test - public void testUserIds_multiUserProfilesAvailable_currentUserIsOtherUser2() { - UserId currentUser = UserId.of(mOtherUser2); + public void testUserIds_multiUserProfilesAvailable_currentUserIsPersonalUserVPlus() { + assumeTrue(SdkLevel.isAtLeastV()); + UserId currentUser = UserId.of(mPersonalUser); + // if available user profiles are {personal , managed, otherUser1 } initializeUserManagerState( - currentUser, Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1, mOtherUser2)); + currentUser, Arrays.asList(mPersonalUser, mManagedUser, mOtherUser1)); InstrumentationRegistry.getInstrumentation() .runOnMainSync( () -> { assertThat(mUserManagerState.isMultiUserProfiles()).isTrue(); + assertThat(mUserManagerState.getCurrentUserProfileId()) - .isEqualTo(UserId.of(mOtherUser2)); + .isEqualTo(UserId.of(mPersonalUser)); List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser), - UserId.of(mOtherUser1)) - : Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser)); + Arrays.asList( + UserId.of(mPersonalUser), + UserId.of(mManagedUser), + UserId.of(mOtherUser1)); assertThat(mUserManagerState.getAllUserProfileIds()) .containsExactlyElementsIn(userIdList); - }); - initializeUserManagerState(currentUser, Arrays.asList(mPersonalUser, mOtherUser2)); - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - assertThat(mUserManagerState.isMultiUserProfiles()).isFalse(); - assertThat(mUserManagerState.getAllUserProfileIds()) - .containsExactlyElementsIn( - Arrays.asList(UserId.of(mPersonalUser))); + assertThat( + mUserManagerState.isManagedUserProfile( + mUserManagerState.getCurrentUserProfileId())) + .isFalse(); }); } @@ -556,56 +561,6 @@ public class UserManagerStateTest { mUserManagerState.getCurrentUserProfileId())) .isTrue(); }); - - // set current user as otherUser2 - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - mUserManagerState.setUserAsCurrentUserProfile(UserId.of(mOtherUser2)); - assertThat(mUserManagerState.getCurrentUserProfileId()) - .isEqualTo(UserId.of(mManagedUser)); - }); - - // set current user as otherUser1 - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - mUserManagerState.setUserAsCurrentUserProfile(UserId.of(mOtherUser1)); - UserHandle currentUserProfile = - SdkLevel.isAtLeastV() ? mOtherUser1 : mManagedUser; - assertThat(mUserManagerState.getCurrentUserProfileId()) - .isEqualTo(UserId.of(currentUserProfile)); - }); - - // set current user as personalUser - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - mUserManagerState.setUserAsCurrentUserProfile(UserId.of(mPersonalUser)); - assertThat(mUserManagerState.getCurrentUserProfileId()) - .isEqualTo(UserId.of(mPersonalUser)); - }); - - // set current user otherUser3 - InstrumentationRegistry.getInstrumentation() - .runOnMainSync( - () -> { - mUserManagerState.setUserAsCurrentUserProfile(UserId.of(mOtherUser3)); - assertThat(mUserManagerState.getCurrentUserProfileId()) - .isEqualTo(UserId.of(mPersonalUser)); - - List<UserId> userIdList = - SdkLevel.isAtLeastV() - ? Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser), - UserId.of(mOtherUser1)) - : Arrays.asList( - UserId.of(mPersonalUser), - UserId.of(mManagedUser)); - assertThat(mUserManagerState.getAllUserProfileIds()) - .containsExactlyElementsIn(userIdList); - }); } private void initializeUserManagerState(UserId current, List<UserHandle> usersOnDevice) { |