summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Richard MacGregor <rmacgregor@google.com> 2025-01-17 17:53:13 -0800
committer Richard MacGregor <rmacgregor@google.com> 2025-01-24 13:37:57 -0800
commit787ec3d945b1557225c76a998f2b16d72104a789 (patch)
treec37d95206d25a3b0b3c3fe4f96178c43cc28ac8a
parent9cb2450013fa4f84f408490ba9c341b8319d9c21 (diff)
Show profilegroup exclusive roles in defaultapps
Fix bug where default apps list opened using work profile context wouldn't show profilegroup exclusive roles when full-user is set as active user LOW_COVERAGE_REASON=FLAG_NOT_ENABLED Bug: 385424712 Flag: com.android.permission.flags.cross_user_role_ux_bugfix_enabled Relnote: N/A Test: atest RoleManagerMultiUserTest Change-Id: I35bb290179432ff44b60bcab53cdf0952aa7573c
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java22
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java13
-rw-r--r--flags/flags.aconfig12
-rw-r--r--tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt181
4 files changed, 210 insertions, 18 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java
index e4a3cbc17..718af090e 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java
@@ -28,12 +28,14 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
+import com.android.permission.flags.Flags;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.permissioncontroller.role.utils.UserUtils;
import com.android.role.controller.model.Role;
import com.android.role.controller.util.RoleFlags;
import java.util.List;
+import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -58,18 +60,21 @@ public class DefaultAppListViewModel extends AndroidViewModel {
super(application);
mUser = Process.myUserHandle();
- boolean isProfileParent = UserUtils.isProfileParent(mUser, application);
+ UserHandle profileParent = UserUtils.getProfileParentOrSelf(mUser, application);
+ UserHandle workProfile = UserUtils.getWorkProfileOrSelf(application);
+ boolean isProfileParent = Objects.equals(mUser, profileParent);
+ boolean isWorkProfile = Objects.equals(mUser, workProfile);
RoleListLiveData liveData = new RoleListLiveData(true, mUser, application);
RoleListSortFunction sortFunction = new RoleListSortFunction(application);
// Only show the work profile section if the current user is a full user
mWorkProfile = isProfileParent ? UserUtils.getWorkProfile(application) : null;
if (RoleFlags.isProfileGroupExclusivityAvailable()) {
+ Predicate<RoleItem> exclusivityPredicate = roleItem ->
+ roleItem.getRole().getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP;
if (mWorkProfile != null) {
// Show profile group exclusive roles from work profile in primary group.
RoleListLiveData workLiveData =
new RoleListLiveData(true, mWorkProfile, application);
- Predicate<RoleItem> exclusivityPredicate = roleItem ->
- roleItem.getRole().getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP;
mLiveData = Transformations.map(
new MergeRoleListLiveData(liveData,
Transformations.map(workLiveData,
@@ -79,6 +84,17 @@ public class DefaultAppListViewModel extends AndroidViewModel {
Transformations.map(workLiveData,
new RoleListFilterFunction(exclusivityPredicate.negate())),
sortFunction);
+ } else if (Flags.crossUserRoleUxBugfixEnabled() && isWorkProfile) {
+ // Show profile group exclusive roles from the profile parent (full user) in primary
+ // group when the current user (primary group) is a work profile
+ RoleListLiveData profileParentLiveData =
+ new RoleListLiveData(true, profileParent, application);
+ mLiveData = Transformations.map(
+ new MergeRoleListLiveData(liveData,
+ Transformations.map(profileParentLiveData,
+ new RoleListFilterFunction(exclusivityPredicate))),
+ sortFunction);
+ mWorkLiveData = null;
} else {
mLiveData = Transformations.map(liveData, sortFunction);
mWorkLiveData = null;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
index f03c31bd8..4d778befb 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
@@ -132,19 +132,6 @@ public class UserUtils {
}
/**
- * Returns whether the user is a parent/full-user or not.
- *
- * @param userHandle the {@code UserHandle} to check is private profile
- * @param context the {@code Context} to retrieve system services
- */
- public static boolean isProfileParent(@NonNull UserHandle userHandle,
- @NonNull Context context) {
- // If profile parent user is null, then original user is the parent
- return com.android.role.controller.util.UserUtils.getProfileParent(userHandle, context)
- == null;
- }
-
- /**
* Returns whether the user is a private profile or not.
*
* @param userHandle the {@code UserHandle} to check is private profile
diff --git a/flags/flags.aconfig b/flags/flags.aconfig
index 45afa5ff4..372fed403 100644
--- a/flags/flags.aconfig
+++ b/flags/flags.aconfig
@@ -119,6 +119,18 @@ flag {
}
flag {
+ name: "cross_user_role_ux_bugfix_enabled"
+ is_exported: true
+ namespace: "permissions"
+ description: "This flag enables cross-user roles support ux bug fixes"
+ bug: "367732307"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "permission_timeline_attribution_label_fix"
is_exported: true
namespace: "permissions"
diff --git a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt
index e8aaddf4c..724549149 100644
--- a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt
+++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt
@@ -16,8 +16,8 @@
package android.app.rolemultiuser.cts
import android.app.Activity
-import android.app.role.cts.RoleManagerUtil
import android.app.role.RoleManager
+import android.app.role.cts.RoleManagerUtil
import android.content.ComponentName
import android.content.Context
import android.content.Intent
@@ -90,7 +90,7 @@ class RoleManagerMultiUserTest {
@Before
@Throws(java.lang.Exception::class)
fun setUp() {
- assumeTrue(RoleManagerUtil.isCddCompliantScreenSize());
+ assumeTrue(RoleManagerUtil.isCddCompliantScreenSize())
installAppForAllUsers()
}
@@ -1085,6 +1085,183 @@ class RoleManagerMultiUserTest {
}
@RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS)
+ @EnsureHasWorkProfile
+ @RequireRunOnPrimaryUser
+ @Test
+ @Throws(java.lang.Exception::class)
+ fun openDefaultAppListFromPrimaryUserAndShowsPrimaryIsDefaultAppInList() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ val targetActiveUser = deviceState.initialUser().userHandle()
+ val future = CallbackFuture()
+ roleManager.addRoleHolderAsUser(
+ PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME,
+ APP_PACKAGE_NAME,
+ 0,
+ targetActiveUser,
+ context.mainExecutor,
+ future,
+ )
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ context.startActivity(
+ Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ getUiDevice().waitForIdle()
+
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ waitFindObject(By.text(targetAppLabel))
+
+ pressBack()
+ } finally {
+ clearDefaultHoldersForTestForAllUsers()
+ clearRoleVisibleForTestForAllUsers()
+ }
+ }
+
+ @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS)
+ @EnsureHasWorkProfile
+ @RequireRunOnPrimaryUser
+ @Test
+ @Throws(java.lang.Exception::class)
+ fun openDefaultAppListFromPrimaryUserAndShowsWorkIsDefaultAppInList() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ val targetActiveUser = deviceState.workProfile().userHandle()
+ val future = CallbackFuture()
+ roleManager.addRoleHolderAsUser(
+ PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME,
+ APP_PACKAGE_NAME,
+ 0,
+ targetActiveUser,
+ context.mainExecutor,
+ future,
+ )
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ context.startActivity(
+ Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ getUiDevice().waitForIdle()
+
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ waitFindObject(By.text(targetAppLabel))
+
+ pressBack()
+ } finally {
+ clearDefaultHoldersForTestForAllUsers()
+ clearRoleVisibleForTestForAllUsers()
+ }
+ }
+
+ @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED,
+ com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED)
+ @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS)
+ @EnsureHasWorkProfile
+ @RequireRunOnWorkProfile
+ @Test
+ @Throws(java.lang.Exception::class)
+ fun openDefaultAppListFromWorkProfileAndShowsPrimaryIsDefaultAppInList() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ val targetActiveUser = deviceState.initialUser().userHandle()
+ val future = CallbackFuture()
+ roleManager.addRoleHolderAsUser(
+ PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME,
+ APP_PACKAGE_NAME,
+ 0,
+ targetActiveUser,
+ context.mainExecutor,
+ future,
+ )
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ context.startActivity(
+ Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ getUiDevice().waitForIdle()
+
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ waitFindObject(By.text(targetAppLabel))
+
+ pressBack()
+ } finally {
+ clearDefaultHoldersForTestForAllUsers()
+ clearRoleVisibleForTestForAllUsers()
+ }
+ }
+
+ @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS)
+ @EnsureHasWorkProfile
+ @RequireRunOnWorkProfile
+ @Test
+ @Throws(java.lang.Exception::class)
+ fun openDefaultAppListFromWorkProfileAndShowsWorkIsDefaultAppInList() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ val targetActiveUser = deviceState.workProfile().userHandle()
+ val future = CallbackFuture()
+ roleManager.addRoleHolderAsUser(
+ PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME,
+ APP_PACKAGE_NAME,
+ 0,
+ targetActiveUser,
+ context.mainExecutor,
+ future,
+ )
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ context.startActivity(
+ Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ getUiDevice().waitForIdle()
+
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ waitFindObject(By.text(targetAppLabel))
+
+ pressBack()
+ } finally {
+ clearDefaultHoldersForTestForAllUsers()
+ clearRoleVisibleForTestForAllUsers()
+ }
+ }
+
+ @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
@EnsureHasWorkProfile
@RequireRunOnPrimaryUser
@Test