summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Richard MacGregor <rmacgregor@google.com> 2024-12-05 16:49:02 -0800
committer Richard MacGregor <rmacgregor@google.com> 2024-12-11 12:22:06 -0800
commite0d6985188ceb5dc60e5ac46d66e71fb4888bb24 (patch)
tree225d9eb5dc5c254b33f42d624587054175d9d073
parentd63f781a4236f33f7737624005ff5e570371a4d7 (diff)
Profile group exclusive roles setting changes
Show profile group exclusive roles in primary default app list section. Show all users for which profile group exclusive role is available in default app screen. LOW_COVERAGE_REASON=FLAG_NOT_ENABLED Relnote: N/A Flag: com.android.permission.flags.cross_user_role_enabled Bug: 378887269 Test: atest RoleManagerTest Test: atest RoleManagerMultiUserTest Change-Id: Id0596f089d8cdcf13941646c547871fce679de18
-rw-r--r--PermissionController/res/xml/roles.xml1
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java31
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java33
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java33
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleListLiveData.java (renamed from PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/MergeRoleListLiveData.java)14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java (renamed from PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/MergeRoleLiveData.java)4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleListFilterFunction.java53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/ReservedForTestingProfileGroupExclusivityRoleUiBehavior.java63
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListViewModel.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt29
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java10
-rw-r--r--tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt268
16 files changed, 548 insertions, 48 deletions
diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml
index 3d858a9c5..0ccd1ce1a 100644
--- a/PermissionController/res/xml/roles.xml
+++ b/PermissionController/res/xml/roles.xml
@@ -1886,6 +1886,7 @@
requestTitle="@string/role_for_testing_profile_group_exclusivity_request_title"
shortLabel="@string/role_for_testing_profile_group_exclusivity_short_label"
showNone="true"
+ uiBehavior="ReservedForTestingProfileGroupExclusivityRoleUiBehavior"
visible="true"/>
<!---
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java
index 91b4e1531..f02b4d90c 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java
@@ -18,6 +18,7 @@ package com.android.role.controller.behavior;
import android.app.role.RoleManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -25,11 +26,14 @@ import androidx.annotation.Nullable;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.PackageUtils;
import com.android.role.controller.util.RoleFlags;
import com.android.role.controller.util.UserUtils;
+import java.util.ArrayList;
import java.util.List;
+// TODO(b/383538899): make minSdk36
public class ReservedForTestingProfileGroupExclusivityRoleBehavior implements RoleBehavior {
@Nullable
@Override
@@ -55,4 +59,31 @@ public class ReservedForTestingProfileGroupExclusivityRoleBehavior implements Ro
return false;
}
}
+
+ @Nullable
+ @Override
+ public List<String> getQualifyingPackagesAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ if (RoleFlags.isProfileGroupExclusivityAvailable()) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ RoleManager userRoleManager = userContext.getSystemService(RoleManager.class);
+ List<String> qualifyingPackageNames =
+ userRoleManager.getDefaultHoldersForTest(role.getName());
+
+ // When getQualifyingPackagesAsUser returns a package that isn't installed, Default App
+ // Settings fails to load. Only return available packages.
+ List<String> availableQualifyingPackageNames = new ArrayList<>();
+ for (int i = 0; i < qualifyingPackageNames.size(); i++) {
+ String qualifyingPackage = qualifyingPackageNames.get(i);
+ ApplicationInfo applicationInfo =
+ PackageUtils.getApplicationInfoAsUser(qualifyingPackage, user, context);
+ if (applicationInfo != null) {
+ availableQualifyingPackageNames.add(qualifyingPackage);
+ }
+ }
+ return availableQualifyingPackageNames;
+ } else {
+ return null;
+ }
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
index 46b148e68..93ad3d31b 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
@@ -46,6 +46,9 @@
"postsubmit": [
{
"name": "CtsRoleTestCases"
+ },
+ {
+ "name": "CtsRoleMultiUserTestCases"
}
],
"mainline-postsubmit": [
@@ -60,6 +63,9 @@
"exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
}
]
+ },
+ {
+ "name": "CtsRoleMultiUserTestCases[com.google.android.permission.apex]"
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
index 2f515f02c..400e1f162 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
@@ -69,6 +69,10 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
+ ".preference.DESCRIPTION";
private static final String PREFERENCE_KEY_OTHER_NFC_SERVICES =
DefaultAppChildFragment.class.getName() + ".preference.OTHER_NFC_SERVICES";
+ private static final String PREFERENCE_EXTRA_PACKAGE_NAME =
+ DefaultAppChildFragment.class.getName() + ".extra.PACKAGE_NAME";
+ private static final String PREFERENCE_EXTRA_USER = DefaultAppChildFragment.class.getName()
+ + ".extra.USER";
@NonNull
private String mRoleName;
@@ -133,7 +137,6 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
Context context = preferenceManager.getContext();
PreferenceScreen preferenceScreen = preferenceFragment.getPreferenceScreen();
- Preference oldDescriptionPreference = null;
ArrayMap<String, Preference> oldPreferences = new ArrayMap<>();
if (preferenceScreen == null) {
preferenceScreen = preferenceManager.createPreferenceScreen(context);
@@ -162,7 +165,9 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
ApplicationInfo qualifyingApplicationInfo = qualifyingApplication.first;
boolean isHolderApplication = qualifyingApplication.second;
- String key = qualifyingApplicationInfo.packageName;
+ int userId =
+ UserHandle.getUserHandleForUid(qualifyingApplicationInfo.uid).getIdentifier();
+ String key = qualifyingApplicationInfo.packageName + "@" + userId;
Drawable icon = Utils.getBadgedIcon(context, qualifyingApplicationInfo);
String title = Utils.getFullAppLabel(qualifyingApplicationInfo, context);
addPreference(key, icon, title, isHolderApplication, qualifyingApplicationInfo,
@@ -205,6 +210,16 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
preference.setPersistent(false);
preference.setOnPreferenceChangeListener((preference2, newValue) -> false);
preference.setOnPreferenceClickListener(this);
+ // In the cases we need this (see #onPreferenceClick()), this should never be null.
+ // This method (addPreference) is used for both legitimate apps and the `NONE` item,
+ // the `NONE` item passes a null applicationinfo object. NFC uses a different preference
+ // method for adding, and a different onclick method
+ if (applicationInfo != null) {
+ Bundle extras = preference.getExtras();
+ extras.putString(PREFERENCE_EXTRA_PACKAGE_NAME, applicationInfo.packageName);
+ extras.putParcelable(PREFERENCE_EXTRA_USER,
+ UserHandle.getUserHandleForUid(applicationInfo.uid));
+ }
} else {
preference = roleApplicationPreference.asTwoStatePreference();
}
@@ -243,22 +258,26 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
if (Objects.equals(key, PREFERENCE_KEY_NONE)) {
mViewModel.setNoneDefaultApp();
} else {
- String packageName = key;
+ String packageName =
+ preference.getExtras().getString(PREFERENCE_EXTRA_PACKAGE_NAME);
+ UserHandle user =
+ preference.getExtras().getParcelable(PREFERENCE_EXTRA_USER);
CharSequence confirmationMessage =
RoleUiBehaviorUtils.getConfirmationMessage(mRole, packageName,
requireContext());
if (confirmationMessage != null) {
- DefaultAppConfirmationDialogFragment.show(packageName, confirmationMessage, this);
+ DefaultAppConfirmationDialogFragment.show(packageName, user, confirmationMessage,
+ this);
} else {
- setDefaultApp(packageName);
+ setDefaultApp(packageName, user);
}
}
return true;
}
@Override
- public void setDefaultApp(@NonNull String packageName) {
- mViewModel.setDefaultApp(packageName);
+ public void setDefaultApp(@NonNull String packageName, @NonNull UserHandle user) {
+ mViewModel.setDefaultApp(packageName, user);
}
private void addNonPaymentNfcServicesPreference(@NonNull PreferenceScreen preferenceScreen,
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java
index 843854bf4..5f399a0b8 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java
@@ -20,9 +20,11 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.os.BundleCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
@@ -32,24 +34,27 @@ import androidx.fragment.app.Fragment;
public class DefaultAppConfirmationDialogFragment extends DialogFragment {
private String mPackageName;
+ private UserHandle mUser;
private CharSequence mMessage;
/**
* Create a new instance of this fragment.
*
* @param packageName the package name of the application
+ * @param user the user the specified package is running in
* @param message the confirmation message
*
* @return a new instance of this fragment
*
- * @see #show(String, CharSequence, Fragment)
+ * @see #show(String, UserHandle, CharSequence, Fragment)
*/
@NonNull
public static DefaultAppConfirmationDialogFragment newInstance(@NonNull String packageName,
- @NonNull CharSequence message) {
+ @NonNull UserHandle user, @NonNull CharSequence message) {
DefaultAppConfirmationDialogFragment fragment = new DefaultAppConfirmationDialogFragment();
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ arguments.putParcelable(Intent.EXTRA_USER, user);
arguments.putCharSequence(Intent.EXTRA_TEXT, message);
fragment.setArguments(arguments);
return fragment;
@@ -59,14 +64,15 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment {
* Show a new instance of this fragment.
*
* @param packageName the package name of the application
+ * @param user the user the specified package is running in
* @param message the confirmation message
* @param fragment the parent fragment
*
- * @see #newInstance(String, CharSequence)
+ * @see #newInstance(String, UserHandle, CharSequence)
*/
- public static void show(@NonNull String packageName, @NonNull CharSequence message,
- @NonNull Fragment fragment) {
- newInstance(packageName, message).show(fragment.getChildFragmentManager(), null);
+ public static void show(@NonNull String packageName, @NonNull UserHandle user,
+ @NonNull CharSequence message, @NonNull Fragment fragment) {
+ newInstance(packageName, user, message).show(fragment.getChildFragmentManager(), null);
}
@Override
@@ -75,6 +81,7 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment {
Bundle arguments = getArguments();
mPackageName = arguments.getString(Intent.EXTRA_PACKAGE_NAME);
+ mUser = BundleCompat.getParcelable(arguments, Intent.EXTRA_USER, UserHandle.class);
mMessage = arguments.getCharSequence(Intent.EXTRA_TEXT);
}
@@ -90,7 +97,7 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment {
private void onOk() {
Listener listener = (Listener) getParentFragment();
- listener.setDefaultApp(mPackageName);
+ listener.setDefaultApp(mPackageName, mUser);
}
/**
@@ -103,6 +110,6 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment {
*
* @param packageName the package name of the application
*/
- void setDefaultApp(@NonNull String packageName);
+ void setDefaultApp(@NonNull String packageName, @NonNull UserHandle user);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java
index 5bc25df54..82253ed00 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java
@@ -30,8 +30,11 @@ import androidx.lifecycle.ViewModel;
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.function.Predicate;
/**
* {@link ViewModel} for the list of default apps.
@@ -55,12 +58,34 @@ public class DefaultAppListViewModel extends AndroidViewModel {
super(application);
mUser = Process.myUserHandle();
+ RoleListLiveData liveData = new RoleListLiveData(true, mUser, application);
RoleListSortFunction sortFunction = new RoleListSortFunction(application);
- mLiveData = Transformations.map(new RoleListLiveData(true, mUser, application),
- sortFunction);
mWorkProfile = UserUtils.getWorkProfile(application);
- mWorkLiveData = mWorkProfile != null ? Transformations.map(new RoleListLiveData(true,
- mWorkProfile, application), sortFunction) : null;
+ if (RoleFlags.isProfileGroupExclusivityAvailable()) {
+ 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,
+ new RoleListFilterFunction(exclusivityPredicate))),
+ sortFunction);
+ mWorkLiveData = Transformations.map(
+ Transformations.map(workLiveData,
+ new RoleListFilterFunction(exclusivityPredicate.negate())),
+ sortFunction);
+ } else {
+ mLiveData = Transformations.map(liveData, sortFunction);
+ mWorkLiveData = null;
+ }
+ } else {
+ mLiveData = Transformations.map(liveData, sortFunction);
+ mWorkLiveData = mWorkProfile != null ? Transformations.map(
+ new RoleListLiveData(true, mWorkProfile, application), sortFunction) : null;
+ }
UserHandle privateProfile = UserUtils.getPrivateProfile(application);
if (privateProfile != null && Utils.shouldShowInSettings(
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
index c89e1f71e..c982f44c6 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
@@ -30,6 +30,7 @@ import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
+import com.android.permissioncontroller.role.utils.UserUtils;
import com.android.role.controller.model.Role;
import java.util.List;
@@ -58,10 +59,23 @@ public class DefaultAppViewModel extends AndroidViewModel {
super(application);
mRole = role;
- mUser = user;
-
- mRoleLiveData = Transformations.map(new RoleLiveData(mRole, mUser, application),
- new RoleSortFunction(application));
+ mUser = mRole.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP
+ ? UserUtils.getProfileParentOrSelf(user, application)
+ : user;
+ RoleLiveData liveData = new RoleLiveData(mRole, mUser, application);
+ RoleSortFunction sortFunction = new RoleSortFunction(application);
+ if (mRole.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP) {
+ UserHandle workProfile = UserUtils.getWorkProfile(application);
+ if (workProfile != null) {
+ RoleLiveData workLiveData = new RoleLiveData(role, workProfile, application);
+ mRoleLiveData = Transformations.map(new MergeRoleLiveData(liveData, workLiveData),
+ sortFunction);
+ } else {
+ mRoleLiveData = Transformations.map(liveData, sortFunction);
+ }
+ } else {
+ mRoleLiveData = Transformations.map(liveData, sortFunction);
+ }
}
@NonNull
@@ -79,13 +93,13 @@ public class DefaultAppViewModel extends AndroidViewModel {
*
* @param packageName the package name of the application
*/
- public void setDefaultApp(@NonNull String packageName) {
+ public void setDefaultApp(@NonNull String packageName, @NonNull UserHandle user) {
if (mManageRoleHolderStateLiveData.getValue() != ManageRoleHolderStateLiveData.STATE_IDLE) {
Log.i(LOG_TAG, "Trying to set default app while another request is on-going");
return;
}
mManageRoleHolderStateLiveData.setRoleHolderAsUser(mRole.getName(), packageName, true, 0,
- mUser, getApplication());
+ user, getApplication());
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/MergeRoleListLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleListLiveData.java
index 0318800f4..0c2d96b2c 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/MergeRoleListLiveData.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleListLiveData.java
@@ -14,16 +14,14 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.ui.specialappaccess;
+package com.android.permissioncontroller.role.ui;
import android.util.ArrayMap;
import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
-import com.android.permissioncontroller.role.ui.RoleItem;
-import com.android.permissioncontroller.role.ui.RoleListLiveData;
-
import java.util.ArrayList;
import java.util.List;
@@ -33,14 +31,14 @@ import java.util.List;
public class MergeRoleListLiveData extends MediatorLiveData<List<RoleItem>> {
@NonNull
- private final RoleListLiveData[] mLiveDatas;
+ private final LiveData<List<RoleItem>>[] mLiveDatas;
- public MergeRoleListLiveData(@NonNull RoleListLiveData... liveDatas) {
+ public MergeRoleListLiveData(@NonNull LiveData<List<RoleItem>>... liveDatas) {
mLiveDatas = liveDatas;
int liveDatasLength = mLiveDatas.length;
for (int i = 0; i < liveDatasLength; i++) {
- RoleListLiveData liveData = mLiveDatas[i];
+ LiveData<List<RoleItem>> liveData = mLiveDatas[i];
addSource(liveData, roleItems -> onRoleListChanged());
}
@@ -50,7 +48,7 @@ public class MergeRoleListLiveData extends MediatorLiveData<List<RoleItem>> {
ArrayMap<String, RoleItem> mergedRoleItemMap = new ArrayMap<>();
int liveDatasLength = mLiveDatas.length;
for (int liveDatasIndex = 0; liveDatasIndex < liveDatasLength; liveDatasIndex++) {
- RoleListLiveData liveData = mLiveDatas[liveDatasIndex];
+ LiveData<List<RoleItem>> liveData = mLiveDatas[liveDatasIndex];
List<RoleItem> roleItems = liveData.getValue();
if (roleItems == null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/MergeRoleLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java
index dab59a1ab..31a02729a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/MergeRoleLiveData.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.ui.specialappaccess;
+package com.android.permissioncontroller.role.ui;
import android.content.pm.ApplicationInfo;
import android.util.Pair;
@@ -22,8 +22,6 @@ import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.lifecycle.MediatorLiveData;
-import com.android.permissioncontroller.role.ui.RoleLiveData;
-
import java.util.ArrayList;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListFilterFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListFilterFunction.java
new file mode 100644
index 000000000..b84fa80b9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListFilterFunction.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.permissioncontroller.role.ui;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import kotlin.jvm.functions.Function1;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * A function for {@link androidx.lifecycle#map(androidx.lifecycle.LiveData, Function1)}
+ * that filters a live data for role list.
+ */
+public class RoleListFilterFunction implements Function1<List<RoleItem>, List<RoleItem>> {
+ private final Predicate<RoleItem> mPredicate;
+
+ public RoleListFilterFunction(@NonNull Predicate<RoleItem> predicate) {
+ mPredicate = predicate;
+ }
+
+ @NonNull
+ @Override
+ public List<RoleItem> invoke(@Nullable List<RoleItem> roleItems) {
+ List<RoleItem> filteredRoleItems = new ArrayList<>();
+ if (roleItems != null) {
+ int roleItemsSize = roleItems.size();
+ for (int i = 0; i < roleItemsSize; i++) {
+ RoleItem roleItem = roleItems.get(i);
+ if (mPredicate.test(roleItem)) {
+ filteredRoleItems.add(roleItem);
+ }
+ }
+ }
+ return filteredRoleItems;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/ReservedForTestingProfileGroupExclusivityRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/ReservedForTestingProfileGroupExclusivityRoleUiBehavior.java
new file mode 100644
index 000000000..abc89edab
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/ReservedForTestingProfileGroupExclusivityRoleUiBehavior.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.permissioncontroller.role.ui.behavior;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
+import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.role.ui.TwoTargetPreference;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.util.UserUtils;
+
+import java.util.List;
+
+public class ReservedForTestingProfileGroupExclusivityRoleUiBehavior implements RoleUiBehavior {
+ @Override
+ public void preparePreferenceAsUser(@NonNull Role role, @NonNull TwoTargetPreference preference,
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ if (!applicationInfos.isEmpty()) {
+ preparePreferenceInternal(preference.asPreference(), applicationInfos.get(0),
+ false, userContext);
+ }
+ }
+
+ @Override
+ public void prepareApplicationPreferenceAsUser(@NonNull Role role,
+ @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ preparePreferenceInternal(preference, applicationInfo, true, userContext);
+ }
+
+ private void preparePreferenceInternal(@NonNull Preference preference,
+ @NonNull ApplicationInfo applicationInfo, boolean setTitle, @NonNull Context context) {
+ String title = Utils.getFullAppLabel(applicationInfo, context) + "@"
+ + UserHandle.getUserHandleForUid(applicationInfo.uid).getIdentifier();
+ if (setTitle) {
+ preference.setTitle(title);
+ } else {
+ preference.setSummary(title);
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListViewModel.java
index ee5a0dbbd..e96fb0943 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListViewModel.java
@@ -26,6 +26,7 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
+import com.android.permissioncontroller.role.ui.MergeRoleListLiveData;
import com.android.permissioncontroller.role.ui.RoleItem;
import com.android.permissioncontroller.role.ui.RoleListLiveData;
import com.android.permissioncontroller.role.ui.RoleListSortFunction;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java
index 0cc00abc1..c12265d43 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java
@@ -33,6 +33,7 @@ import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData;
+import com.android.permissioncontroller.role.ui.MergeRoleLiveData;
import com.android.permissioncontroller.role.ui.RoleLiveData;
import com.android.permissioncontroller.role.ui.RoleSortFunction;
import com.android.permissioncontroller.role.utils.UserUtils;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt
index a47719cf7..610745674 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt
@@ -34,7 +34,7 @@ class WearDefaultAppHelper(
val user: UserHandle,
val role: Role,
val viewModel: DefaultAppViewModel,
- val confirmDialogViewModel: DefaultAppConfirmDialogViewModel
+ val confirmDialogViewModel: DefaultAppConfirmDialogViewModel,
) {
fun getTitle() = context.getString(role.labelResource)
@@ -46,7 +46,7 @@ class WearDefaultAppHelper(
context = context,
defaultLabel = context.getString(R.string.default_app_none),
checked = !hasHolderApplication(qualifyingApplications),
- onDefaultCheckChanged = { _ -> viewModel.setNoneDefaultApp() }
+ onDefaultCheckChanged = { _ -> viewModel.setNoneDefaultApp() },
)
.apply { icon = context.getDrawable(R.drawable.ic_remove_circle) }
} else {
@@ -67,19 +67,24 @@ class WearDefaultAppHelper(
onDefaultCheckChanged = { _ ->
run {
val packageName = appInfo.packageName
+ val user = UserHandle.getUserHandleForUid(appInfo.uid)
val confirmationMessage =
RoleUiBehaviorUtils.getConfirmationMessage(
role,
packageName,
- context
+ context,
)
if (confirmationMessage != null) {
- showConfirmDialog(packageName, confirmationMessage.toString())
+ showConfirmDialog(
+ packageName,
+ user,
+ confirmationMessage.toString(),
+ )
} else {
- setDefaultApp(packageName)
+ setDefaultApp(packageName, user)
}
}
- }
+ },
)
.apply {
icon = appInfo.loadIcon(context.packageManager)
@@ -91,22 +96,22 @@ class WearDefaultAppHelper(
this,
appInfo,
user,
- context
+ context,
)
}
}
.toList()
}
- private fun showConfirmDialog(packageName: String, message: String) {
+ private fun showConfirmDialog(packageName: String, userHandle: UserHandle, message: String) {
confirmDialogViewModel.confirmDialogArgs =
ConfirmDialogArgs(
message = message,
onOkButtonClick = {
- setDefaultApp(packageName)
+ setDefaultApp(packageName, userHandle)
dismissConfirmDialog()
},
- onCancelButtonClick = { dismissConfirmDialog() }
+ onCancelButtonClick = { dismissConfirmDialog() },
)
confirmDialogViewModel.showConfirmDialogLiveData.value = true
}
@@ -116,8 +121,8 @@ class WearDefaultAppHelper(
confirmDialogViewModel.showConfirmDialogLiveData.value = false
}
- private fun setDefaultApp(packageName: String) {
- viewModel.setDefaultApp(packageName)
+ private fun setDefaultApp(packageName: String, user: UserHandle) {
+ viewModel.setDefaultApp(packageName, user)
}
fun getDescription() = context.getString(role.descriptionResource)
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
index 339b2a12a..f3ae21578 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
@@ -37,6 +37,16 @@ public class UserUtils {
private UserUtils() {}
/**
+ * Returns the parent of a given user, or user if it has no parent (e.g. it is the primary
+ * user)
+ */
+ @NonNull
+ public static UserHandle getProfileParentOrSelf(@NonNull UserHandle user,
+ @NonNull Context context) {
+ return com.android.role.controller.util.UserUtils.getProfileParentOrSelf(user, context);
+ }
+
+ /**
* Get the work profile of current user, if any.
*
* @param context the {@code Context} to retrieve system services
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 e33e95706..a70bc070a 100644
--- a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt
+++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt
@@ -17,10 +17,14 @@ package android.app.rolemultiuser.cts
import android.app.role.RoleManager
import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Build
import android.os.Process
import android.os.UserHandle
+import android.provider.Settings
import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile
import com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile
import com.android.bedstead.enterprise.workProfile
@@ -43,8 +47,12 @@ import com.android.bedstead.permissions.CommonPermissions.MANAGE_DEFAULT_APPLICA
import com.android.bedstead.permissions.CommonPermissions.MANAGE_ROLE_HOLDERS
import com.android.bedstead.permissions.annotations.EnsureDoesNotHavePermission
import com.android.bedstead.permissions.annotations.EnsureHasPermission
+import com.android.compatibility.common.util.DisableAnimationRule
+import com.android.compatibility.common.util.FreezeRotationRule
import com.android.compatibility.common.util.SystemUtil
import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.Objects
@@ -555,6 +563,234 @@ class RoleManagerMultiUserTest {
assertExpectedProfileHasRoleUsingGetDefaultApplication(targetActiveUser)
}
+ @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 openDefaultAppListAndSetDefaultAppThenIsDefaultApp() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ 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()
+ waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click()
+ getUiDevice().waitForIdle()
+
+ val targetActiveUser = users().current().userHandle()
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ if (isWatch) {
+ waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click()
+ } else {
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ .click()
+ }
+
+ if (isWatch) {
+ waitFindObject(
+ By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel))
+ )
+ } else {
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ }
+
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ pressBack()
+ 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 openDefaultAppListAndSetWorkDefaultAppThenIsDefaultApp() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ 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()
+ waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click()
+ getUiDevice().waitForIdle()
+
+ val targetActiveUser = deviceState.workProfile().userHandle()
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ if (isWatch) {
+ waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click()
+ } else {
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ .click()
+ }
+
+ if (isWatch) {
+ waitFindObject(
+ By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel))
+ )
+ } else {
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ }
+
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ pressBack()
+ 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 openDefaultAppListAndSetDefaultAppThenIsDefaultAppInList() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ 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()
+ waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click()
+ getUiDevice().waitForIdle()
+
+ val targetActiveUser = users().current().userHandle()
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ if (isWatch) {
+ waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click()
+ waitFindObject(
+ By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel))
+ )
+ } else {
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ .click()
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ }
+ pressBack()
+
+ waitFindObject(By.text(targetAppLabel))
+
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ 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 openDefaultAppListAndSetWorkDefaultAppThenIsDefaultAppInList() {
+ try {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ setDefaultHoldersForTestForAllUsers()
+ setRoleVisibleForTestForAllUsers()
+
+ 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()
+ waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click()
+ getUiDevice().waitForIdle()
+
+ val targetActiveUser = deviceState.workProfile().userHandle()
+ val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}"
+ if (isWatch) {
+ waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click()
+ waitFindObject(
+ By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel))
+ )
+ } else {
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ .click()
+ waitFindObject(
+ By.clickable(true)
+ .hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(targetAppLabel))
+ )
+ }
+ pressBack()
+
+ waitFindObject(By.text(targetAppLabel))
+
+ assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME))
+ .isEqualTo(targetActiveUser)
+ assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser)
+
+ pressBack()
+ } finally {
+ clearDefaultHoldersForTestForAllUsers()
+ clearRoleVisibleForTestForAllUsers()
+ }
+ }
+
@Throws(java.lang.Exception::class)
private fun installAppForAllUsers() {
SystemUtil.runShellCommandOrThrow("pm install -r --user all $APP_APK_PATH")
@@ -564,6 +800,11 @@ class RoleManagerMultiUserTest {
SystemUtil.runShellCommand("pm uninstall $APP_PACKAGE_NAME")
}
+ private fun pressBack() {
+ getUiDevice().pressBack()
+ getUiDevice().waitForIdle()
+ }
+
private fun assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(
expectedActiveUser: UserHandle
) {
@@ -641,6 +882,20 @@ class RoleManagerMultiUserTest {
}
}
+ private fun setRoleVisibleForTestForAllUsers() {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ for (userRoleManager in users().all().map { getRoleManagerForUser(it.userHandle()) }) {
+ userRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, true)
+ }
+ }
+
+ private fun clearRoleVisibleForTestForAllUsers() {
+ // Set test default role holder. Ensures fallbacks to a default holder
+ for (userRoleManager in users().all().map { getRoleManagerForUser(it.userHandle()) }) {
+ userRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false)
+ }
+ }
+
private fun getRoleManagerForUser(user: UserHandle): RoleManager {
val userContext = context.createContextAsUser(user, 0)
return userContext.getSystemService(RoleManager::class.java)
@@ -656,13 +911,26 @@ class RoleManagerMultiUserTest {
private const val TIMEOUT_MILLIS: Long = (15 * 1000).toLong()
private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME =
RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY
+ private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL =
+ "Test profile group exclusive role app"
private const val PRIVATE_PROFILE_TYPE_NAME = "android.os.usertype.profile.PRIVATE"
private const val APP_APK_PATH: String =
"/data/local/tmp/cts-role/CtsRoleMultiUserTestApp.apk"
private const val APP_PACKAGE_NAME: String = "android.app.rolemultiuser.cts.app"
+ private const val APP_LABEL: String = "CtsRoleMultiUserTestApp"
+
private val context: Context = context().instrumentedContext()
private val roleManager: RoleManager = context.getSystemService(RoleManager::class.java)
+ private val packageManager: PackageManager = context.packageManager
+ private val isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
@JvmField @ClassRule @Rule val deviceState = DeviceState()
+
+ @JvmField
+ @ClassRule
+ @Rule
+ var disableAnimationRule: DisableAnimationRule = DisableAnimationRule()
+
+ @JvmField @ClassRule @Rule var freezeRotationRule: FreezeRotationRule = FreezeRotationRule()
}
}