diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 179fc5c661a5f..6ba811e077ac8 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -268,15 +268,17 @@ public class CrossProfileApps {
}
/**
- * Returns whether the calling package can request user consent to interact across profiles.
+ * Returns whether the calling package can request to navigate the user to
+ * the relevant settings page to request user consent to interact across profiles.
*
- *
If {@code true}, user consent can be obtained via {@link
+ *
If {@code true}, the navigation intent can be obtained via {@link
* #createRequestInteractAcrossProfilesIntent()}. The package can then listen to {@link
* #ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED} broadcasts.
*
*
Specifically, returns whether the following are all true:
*
- * - {@link #getTargetUserProfiles()} returns a non-empty list for the calling user.
+ * - {@code UserManager#getEnabledProfileIds(int)} ()} returns at least one other profile for
+ * the calling user.
* - The calling app has requested
* {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} in its manifest.
* - The calling package has either been whitelisted by default by the OEM or has been
@@ -285,6 +287,10 @@ public class CrossProfileApps {
*
*
*
+ * Note that in order for the user to be able to grant the consent, the requesting package
+ * must be whitelisted by the admin or the OEM and installed in the other profile. If this is
+ * not the case the user will be shown a message explaining why they can't grant the consent.
+ *
*
Note that user consent could already be granted if given a return value of {@code true}.
* The package's current ability to interact across profiles can be checked with {@link
* #canInteractAcrossProfiles()}.
@@ -421,6 +427,23 @@ public class CrossProfileApps {
}
}
+ /**
+ * Returns {@code true} if the given package has requested
+ * {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} and the user has at least one
+ * other profile in the same profile group.
+ *
+ *
This differs from {@link #canConfigureInteractAcrossProfiles(String)} since it will
+ * not return {@code false} if the app is not whitelisted or not installed in the other profile.
+ *
+ * @hide
+ */
+ public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) {
+ try {
+ return mService.canUserAttemptToConfigureInteractAcrossProfiles(packageName);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
/**
* For each of the packages defined in {@code previousCrossProfilePackages} but not included in
* {@code newCrossProfilePackages}, resets the app-op for {@link android.Manifest.permission
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 4cecb30990e6c..9b0dae221538b 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -38,5 +38,6 @@ interface ICrossProfileApps {
boolean canRequestInteractAcrossProfiles(in String callingPackage);
void setInteractAcrossProfilesAppOp(in String packageName, int newMode);
boolean canConfigureInteractAcrossProfiles(in String packageName);
+ boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName);
void resetInteractAcrossProfilesAppOps(in List packageNames);
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 83da38195053a..7069818e38941 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -249,16 +249,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
}
private boolean canRequestInteractAcrossProfilesUnchecked(String packageName) {
- List targetUserProfiles =
- getTargetUserProfilesUnchecked(packageName, mInjector.getCallingUserId());
- if (targetUserProfiles.isEmpty()) {
+ final int[] enabledProfileIds =
+ mInjector.getUserManager().getEnabledProfileIds(mInjector.getCallingUserId());
+ if (enabledProfileIds.length < 2) {
return false;
}
- if (!hasRequestedAppOpPermission(
- AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) {
- return false;
- }
- return isCrossProfilePackageWhitelisted(packageName);
+ return hasRequestedAppOpPermission(
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName);
}
private boolean hasRequestedAppOpPermission(String permission, String packageName) {
@@ -540,6 +537,17 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return isCrossProfilePackageWhitelisted(packageName);
}
+ @Override
+ public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) {
+ final int[] profileIds = mInjector.getUserManager().getProfileIds(
+ mInjector.getCallingUserId(), /* enabledOnly= */ false);
+ if (profileIds.length < 2) {
+ return false;
+ }
+ return hasRequestedAppOpPermission(
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName);
+ }
+
private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) {
return mInjector.withCleanCallingIdentity(() -> {
final int[] profileIds =
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index fa0febd7f20f1..acdb681421785 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -419,6 +419,38 @@ public class CrossProfileAppsServiceImplRoboTest {
.isTrue();
}
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsTrue() {
+ mockUninstallCrossProfileAppFromWorkProfile();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()
+ throws Exception {
+ mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsTrue() {
+ mockCrossProfileAppNotWhitelisted();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() {
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) {
explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode);
}