summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mark Renouf <mrenouf@google.com> 2024-04-19 18:12:41 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-04-19 18:12:41 +0000
commit767be2d49a2576aa980a4761d9f7c484a9fc18d6 (patch)
treec850c674de5ab9354b6f55abc760fbf5763fe15c
parent16b13dc38e94325fcaee07bc94470dc5c7e4b10f (diff)
parent4ca5dc54a57d61b8bd116a2259f51a7cdc5ea184 (diff)
Merge "Fix "NoAppsAvailableEmptyStateProvider" message for Private" into main
-rw-r--r--java/res/values/strings.xml3
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java7
-rw-r--r--java/src/com/android/intentresolver/ProfileAvailability.kt18
-rw-r--r--java/src/com/android/intentresolver/ResolverActivity.java11
-rw-r--r--java/src/com/android/intentresolver/data/repository/DevicePolicyResources.kt43
-rw-r--r--java/src/com/android/intentresolver/emptystate/NoAppsAvailableEmptyStateProvider.java101
-rw-r--r--java/src/com/android/intentresolver/ui/ProfilePagerResources.kt8
7 files changed, 112 insertions, 79 deletions
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 5c1210b7..17a514d7 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -295,6 +295,9 @@
<!-- Error message. This text lets the user know that their current personal apps don't support the specific content. [CHAR LIMIT=NONE] -->
<string name="resolver_no_personal_apps_available">No personal apps</string>
+ <!-- Error message. This text lets the user know that their current private apps don't support the specific content. [CHAR LIMIT=NONE] -->
+ <string name="resolver_no_private_apps_available">No private apps</string>
+
<!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
<string name="miniresolver_open_in_personal">Open <xliff:g id="app" example="YouTube">%s</xliff:g> in your personal profile?</string>
<!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 7e2c9c5a..43d28761 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -1051,11 +1051,10 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
getMetricsCategory());
EmptyStateProvider noAppsEmptyStateProvider = new NoAppsAvailableEmptyStateProvider(
- this,
- profileHelper.getWorkHandle(),
- profileHelper.getPersonalHandle(),
+ mProfiles,
+ mProfileAvailability,
getMetricsCategory(),
- profileHelper.getTabOwnerUserHandleForLaunch()
+ mProfilePagerResources
);
// Return composite provider, the order matters (the higher, the more priority)
diff --git a/java/src/com/android/intentresolver/ProfileAvailability.kt b/java/src/com/android/intentresolver/ProfileAvailability.kt
index cf3e566e..c8e78552 100644
--- a/java/src/com/android/intentresolver/ProfileAvailability.kt
+++ b/java/src/com/android/intentresolver/ProfileAvailability.kt
@@ -53,6 +53,24 @@ class ProfileAvailability(
}
}
+ /**
+ * The number of profiles which are visible. All profiles count except for private which is
+ * hidden when locked.
+ */
+ fun visibleProfileCount() =
+ runBlocking(background) {
+ val availability = userInteractor.availability.first()
+ val profiles = userInteractor.profiles.first()
+ profiles
+ .filter {
+ when (it.type) {
+ Profile.Type.PRIVATE -> availability[it] == true
+ else -> true
+ }
+ }
+ .size
+ }
+
/** Used by WorkProfilePausedEmptyStateProvider */
fun requestQuietModeState(profile: Profile, quietMode: Boolean) {
val enableProfile = !quietMode
diff --git a/java/src/com/android/intentresolver/ResolverActivity.java b/java/src/com/android/intentresolver/ResolverActivity.java
index 2f1f8ee5..4e763f94 100644
--- a/java/src/com/android/intentresolver/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/ResolverActivity.java
@@ -112,6 +112,7 @@ import com.android.intentresolver.profiles.ResolverMultiProfilePagerAdapter;
import com.android.intentresolver.profiles.TabConfig;
import com.android.intentresolver.shared.model.Profile;
import com.android.intentresolver.ui.ActionTitle;
+import com.android.intentresolver.ui.ProfilePagerResources;
import com.android.intentresolver.ui.model.ActivityModel;
import com.android.intentresolver.ui.model.ResolverRequest;
import com.android.intentresolver.ui.viewmodel.ResolverViewModel;
@@ -153,6 +154,7 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
@Inject public ResolverHelper mResolverHelper;
@Inject public PackageManager mPackageManager;
@Inject public DevicePolicyResources mDevicePolicyResources;
+ @Inject public ProfilePagerResources mProfilePagerResources;
@Inject public IntentForwarding mIntentForwarding;
@Inject public FeatureFlags mFeatureFlags;
@@ -963,12 +965,11 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
},
getMetricsCategory());
- final EmptyStateProvider noAppsEmptyStateProvider = new NoAppsAvailableEmptyStateProvider(
- this,
- workProfileUserHandle,
- mProfiles.getPersonalHandle(),
+ EmptyStateProvider noAppsEmptyStateProvider = new NoAppsAvailableEmptyStateProvider(
+ mProfiles,
+ mProfileAvailability,
getMetricsCategory(),
- mProfiles.getTabOwnerUserHandleForLaunch()
+ mProfilePagerResources
);
// Return composite provider, the order matters (the higher, the more priority)
diff --git a/java/src/com/android/intentresolver/data/repository/DevicePolicyResources.kt b/java/src/com/android/intentresolver/data/repository/DevicePolicyResources.kt
index c396b720..75faa068 100644
--- a/java/src/com/android/intentresolver/data/repository/DevicePolicyResources.kt
+++ b/java/src/com/android/intentresolver/data/repository/DevicePolicyResources.kt
@@ -18,6 +18,9 @@ package com.android.intentresolver.data.repository
import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL
import android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK
+import android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE
+import android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS
+import android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS
import android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB
import android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB_ACCESSIBILITY
import android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PROFILE_NOT_SUPPORTED
@@ -83,6 +86,46 @@ constructor(
)
}
+ val noPersonalApps by lazy {
+ requireNotNull(
+ policyResources.getString(RESOLVER_NO_PERSONAL_APPS) {
+ resources.getString(R.string.resolver_no_personal_apps_available)
+ }
+ )
+ }
+
+ val noWorkApps by lazy {
+ requireNotNull(
+ policyResources.getString(RESOLVER_NO_WORK_APPS) {
+ resources.getString(R.string.resolver_no_work_apps_available)
+ }
+ )
+ }
+
+ val crossProfileBlocked by lazy {
+ requireNotNull(
+ policyResources.getString(RESOLVER_CROSS_PROFILE_BLOCKED_TITLE) {
+ resources.getString(R.string.resolver_cross_profile_blocked)
+ }
+ )
+ }
+
+ fun toPersonalBlockedByPolicyMessage(sendAction: Boolean): String {
+ return if (sendAction) {
+ resources.getString(R.string.resolver_cant_share_with_personal_apps_explanation)
+ } else {
+ resources.getString(R.string.resolver_cant_access_personal_apps_explanation)
+ }
+ }
+
+ fun toWorkBlockedByPolicyMessage(sendAction: Boolean): String {
+ return if (sendAction) {
+ resources.getString(R.string.resolver_cant_share_with_work_apps_explanation)
+ } else {
+ resources.getString(R.string.resolver_cant_access_work_apps_explanation)
+ }
+ }
+
fun getWorkProfileNotSupportedMessage(launcherName: String): String {
return requireNotNull(
policyResources.getString(
diff --git a/java/src/com/android/intentresolver/emptystate/NoAppsAvailableEmptyStateProvider.java b/java/src/com/android/intentresolver/emptystate/NoAppsAvailableEmptyStateProvider.java
index 7bfea4f8..af9d56d1 100644
--- a/java/src/com/android/intentresolver/emptystate/NoAppsAvailableEmptyStateProvider.java
+++ b/java/src/com/android/intentresolver/emptystate/NoAppsAvailableEmptyStateProvider.java
@@ -16,24 +16,22 @@
package com.android.intentresolver.emptystate;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
+
+import static com.android.intentresolver.shared.model.Profile.Type.PERSONAL;
+
+import static java.util.Objects.requireNonNull;
import android.app.admin.DevicePolicyEventLogger;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.stats.devicepolicy.nano.DevicePolicyEnums;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.android.intentresolver.R;
-import com.android.intentresolver.ResolvedComponentInfo;
+import com.android.intentresolver.ProfileAvailability;
+import com.android.intentresolver.ProfileHelper;
import com.android.intentresolver.ResolverListAdapter;
-
-import java.util.List;
+import com.android.intentresolver.shared.model.Profile;
+import com.android.intentresolver.ui.ProfilePagerResources;
/**
* Chooser/ResolverActivity empty state provider that returns empty state which is shown when
@@ -41,77 +39,40 @@ import java.util.List;
*/
public class NoAppsAvailableEmptyStateProvider implements EmptyStateProvider {
- @NonNull
- private final Context mContext;
- @Nullable
- private final UserHandle mWorkProfileUserHandle;
- @Nullable
- private final UserHandle mPersonalProfileUserHandle;
- @NonNull
- private final String mMetricsCategory;
- @NonNull
- private final UserHandle mTabOwnerUserHandleForLaunch;
-
- public NoAppsAvailableEmptyStateProvider(@NonNull Context context,
- @Nullable UserHandle workProfileUserHandle,
- @Nullable UserHandle personalProfileUserHandle, @NonNull String metricsCategory,
- @NonNull UserHandle tabOwnerUserHandleForLaunch) {
- mContext = context;
- mWorkProfileUserHandle = workProfileUserHandle;
- mPersonalProfileUserHandle = personalProfileUserHandle;
+ @NonNull private final String mMetricsCategory;
+ private final ProfilePagerResources mProfilePagerResources;
+ private final ProfileHelper mProfileHelper;
+ private final ProfileAvailability mProfileAvailability;
+
+ public NoAppsAvailableEmptyStateProvider(
+ ProfileHelper profileHelper,
+ ProfileAvailability profileAvailability,
+ @NonNull String metricsCategory,
+ ProfilePagerResources profilePagerResources) {
+ mProfileHelper = profileHelper;
+ mProfileAvailability = profileAvailability;
mMetricsCategory = metricsCategory;
- mTabOwnerUserHandleForLaunch = tabOwnerUserHandleForLaunch;
+ mProfilePagerResources = profilePagerResources;
}
- @Nullable
+ @NonNull
@Override
- @SuppressWarnings("ReferenceEquality")
public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
UserHandle listUserHandle = resolverListAdapter.getUserHandle();
-
- if (mWorkProfileUserHandle != null
- && (mTabOwnerUserHandleForLaunch.equals(listUserHandle)
- || !hasAppsInOtherProfile(resolverListAdapter))) {
-
- String title;
- if (listUserHandle == mPersonalProfileUserHandle) {
- title = mContext.getSystemService(
- DevicePolicyManager.class).getResources().getString(
- RESOLVER_NO_PERSONAL_APPS,
- () -> mContext.getString(R.string.resolver_no_personal_apps_available));
- } else {
- title = mContext.getSystemService(
- DevicePolicyManager.class).getResources().getString(
- RESOLVER_NO_WORK_APPS,
- () -> mContext.getString(R.string.resolver_no_work_apps_available));
- }
-
+ if (mProfileAvailability.visibleProfileCount() == 1) {
+ return new DefaultEmptyState();
+ } else {
+ Profile.Type profileType =
+ requireNonNull(mProfileHelper.findProfileType(listUserHandle));
+ String title = mProfilePagerResources.noAppsMessage(profileType);
return new NoAppsAvailableEmptyState(
- title, mMetricsCategory,
- /* isPersonalProfile= */ listUserHandle == mPersonalProfileUserHandle
+ title,
+ mMetricsCategory,
+ /* isPersonalProfile= */ profileType == PERSONAL
);
- } else if (mWorkProfileUserHandle == null) {
- // Return default empty state without tracking
- return new DefaultEmptyState();
}
-
- return null;
}
- private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) {
- if (mWorkProfileUserHandle == null) {
- return false;
- }
- List<ResolvedComponentInfo> resolversForIntent =
- adapter.getResolversForUser(mTabOwnerUserHandleForLaunch);
- for (ResolvedComponentInfo info : resolversForIntent) {
- ResolveInfo resolveInfo = info.getResolveInfoAt(0);
- if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) {
- return true;
- }
- }
- return false;
- }
public static class DefaultEmptyState implements EmptyState {
@Override
diff --git a/java/src/com/android/intentresolver/ui/ProfilePagerResources.kt b/java/src/com/android/intentresolver/ui/ProfilePagerResources.kt
index baab9a4c..0d07af8f 100644
--- a/java/src/com/android/intentresolver/ui/ProfilePagerResources.kt
+++ b/java/src/com/android/intentresolver/ui/ProfilePagerResources.kt
@@ -50,4 +50,12 @@ constructor(
Profile.Type.PRIVATE -> privateTabAccessibilityLabel
}
}
+
+ fun noAppsMessage(type: Profile.Type): String {
+ return when (type) {
+ Profile.Type.PERSONAL -> devicePolicyResources.noPersonalApps
+ Profile.Type.WORK -> devicePolicyResources.noWorkApps
+ Profile.Type.PRIVATE -> resources.getString(R.string.resolver_no_private_apps_available)
+ }
+ }
}