summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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()
}
}