summaryrefslogtreecommitdiff
path: root/PermissionController/src
diff options
context:
space:
mode:
author Dario Freni <dariofreni@google.com> 2025-02-05 16:04:43 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-05 16:04:43 -0800
commit709edc1e4b354717290d6234238e1c0478484e54 (patch)
tree04ef7eaabbc5ef9b67b5417258515d5d3703de40 /PermissionController/src
parent0eeed4de6203c5d90f9228ee55bdd8cddcb5e0b5 (diff)
parent9b11f01bc5fa240369136053641558ac89502ed9 (diff)
Merge "Add recommended category for default app page" into main
Diffstat (limited to 'PermissionController/src')
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java78
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java25
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java15
5 files changed, 146 insertions, 11 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
index 5f870b1e3..268633c4f 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
@@ -32,6 +32,7 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
@@ -39,6 +40,7 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.flags.Flags;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.permissioncontroller.role.utils.PackageUtils;
@@ -63,6 +65,10 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
implements DefaultAppConfirmationDialogFragment.Listener,
Preference.OnPreferenceClickListener {
+ private static final String PREFERENCE_KEY_RECOMMENDED_CATEGORY =
+ DefaultAppChildFragment.class.getName() + ".preference.RECOMMENDED_CATEGORY";
+ private static final String PREFERENCE_KEY_OTHERS_CATEGORY =
+ DefaultAppChildFragment.class.getName() + ".preference.OTHERS_CATEGORY";
private static final String PREFERENCE_KEY_NONE = DefaultAppChildFragment.class.getName()
+ ".preference.NONE";
private static final String PREFERENCE_KEY_DESCRIPTION = DefaultAppChildFragment.class.getName()
@@ -125,14 +131,21 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
ViewModelProvider.Factory viewModelFactory = new DefaultAppViewModel.Factory(mRole, mUser,
activity.getApplication());
mViewModel = new ViewModelProvider(this, viewModelFactory).get(DefaultAppViewModel.class);
+ mViewModel.getRecommendedLiveData().observe(this,
+ applicationItems -> onApplicationListChanged());
mViewModel.getLiveData().observe(this, applicationItems -> onApplicationListChanged());
mViewModel.getManageRoleHolderStateLiveData().observe(this,
this::onManageRoleHolderStateChanged);
}
private void onApplicationListChanged() {
- List<RoleApplicationItem> applicationItems = mViewModel.getLiveData().getValue();
- if (applicationItems == null) {
+ List<RoleApplicationItem> recommendedApplicationItems =
+ mViewModel.getRecommendedLiveData().getValue();
+ if (recommendedApplicationItems == null) {
+ return;
+ }
+ List<RoleApplicationItem> otherApplicationItems = mViewModel.getLiveData().getValue();
+ if (otherApplicationItems == null) {
return;
}
@@ -141,17 +154,43 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
Context context = preferenceManager.getContext();
PreferenceScreen preferenceScreen = preferenceFragment.getPreferenceScreen();
+ PreferenceCategory oldRecommendedPreferenceCategory = null;
+ PreferenceCategory oldOthersPreferenceCategory = null;
ArrayMap<String, Preference> oldPreferences = new ArrayMap<>();
if (preferenceScreen == null) {
preferenceScreen = preferenceManager.createPreferenceScreen(context);
preferenceFragment.setPreferenceScreen(preferenceScreen);
} else {
+ if (Flags.defaultAppsRecommendationEnabled()) {
+ oldRecommendedPreferenceCategory =
+ preferenceScreen.findPreference(PREFERENCE_KEY_RECOMMENDED_CATEGORY);
+ clearPreferenceCategory(oldRecommendedPreferenceCategory, oldPreferences);
+ oldOthersPreferenceCategory =
+ preferenceScreen.findPreference(PREFERENCE_KEY_OTHERS_CATEGORY);
+ clearPreferenceCategory(oldOthersPreferenceCategory, oldPreferences);
+ }
clearPreferences(preferenceScreen, oldPreferences);
}
- boolean noneChecked = !hasHolderApplication(applicationItems);
- addNonePreferenceIfNeeded(preferenceScreen, noneChecked, oldPreferences, context);
- addApplicationPreferences(preferenceScreen, applicationItems, oldPreferences, context);
+ if (Flags.defaultAppsRecommendationEnabled() && !recommendedApplicationItems.isEmpty()) {
+ addApplicationPreferenceCategory(oldRecommendedPreferenceCategory,
+ PREFERENCE_KEY_RECOMMENDED_CATEGORY,
+ getString(R.string.default_app_recommended), preferenceScreen, false, false,
+ recommendedApplicationItems, oldPreferences, context);
+ if (mRole.shouldShowNone() || !otherApplicationItems.isEmpty()) {
+ boolean noneChecked = !(hasHolderApplication(recommendedApplicationItems)
+ || hasHolderApplication(otherApplicationItems));
+ addApplicationPreferenceCategory(oldOthersPreferenceCategory,
+ PREFERENCE_KEY_OTHERS_CATEGORY, getString(R.string.default_app_others),
+ preferenceScreen, true, noneChecked, otherApplicationItems, oldPreferences,
+ context);
+ }
+ } else {
+ boolean noneChecked = !hasHolderApplication(otherApplicationItems);
+ addNonePreferenceIfNeeded(preferenceScreen, noneChecked, oldPreferences, context);
+ addApplicationPreferences(preferenceScreen, otherApplicationItems, oldPreferences,
+ context);
+ }
addNonPaymentNfcServicesPreference(preferenceScreen, oldPreferences, context);
addDescriptionPreference(preferenceScreen, oldPreferences);
@@ -159,6 +198,16 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
preferenceFragment.onPreferenceScreenChanged();
}
+ private static void clearPreferenceCategory(@Nullable PreferenceCategory preferenceCategory,
+ @NonNull ArrayMap<String, Preference> oldPreferences) {
+ if (preferenceCategory == null) {
+ return;
+ }
+ clearPreferences(preferenceCategory, oldPreferences);
+ preferenceCategory.getParent().removePreference(preferenceCategory);
+ preferenceCategory.setOrder(Preference.DEFAULT_ORDER);
+ }
+
private static void clearPreferences(@NonNull PreferenceGroup preferenceGroup,
@NonNull ArrayMap<String, Preference> oldPreferences) {
for (int i = preferenceGroup.getPreferenceCount() - 1; i >= 0; --i) {
@@ -170,6 +219,25 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
}
}
+ private void addApplicationPreferenceCategory(
+ @Nullable PreferenceCategory oldPreferenceCategory, @NonNull String key,
+ @Nullable String title, @NonNull PreferenceScreen preferenceScreen,
+ boolean addNonePreferenceIfNeeded, boolean noneChecked,
+ @NonNull List<RoleApplicationItem> applicationItems,
+ @NonNull ArrayMap<String, Preference> oldPreferences, @NonNull Context context) {
+ PreferenceCategory preferenceCategory = oldPreferenceCategory;
+ if (preferenceCategory == null) {
+ preferenceCategory = new PreferenceCategory(context);
+ preferenceCategory.setKey(key);
+ preferenceCategory.setTitle(title);
+ }
+ preferenceScreen.addPreference(preferenceCategory);
+ if (addNonePreferenceIfNeeded) {
+ addNonePreferenceIfNeeded(preferenceCategory, noneChecked, oldPreferences, context);
+ }
+ addApplicationPreferences(preferenceCategory, applicationItems, oldPreferences, context);
+ }
+
private static boolean hasHolderApplication(
@NonNull List<RoleApplicationItem> applicationItems) {
int applicationItemsSize = applicationItems.size();
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
index 790c55d84..f4ba94f1d 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
@@ -28,10 +28,12 @@ import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
import com.android.permissioncontroller.role.utils.UserUtils;
import com.android.role.controller.model.Role;
import java.util.List;
+import java.util.function.Predicate;
/**
* {@link ViewModel} for a default app.
@@ -46,6 +48,9 @@ public class DefaultAppViewModel extends AndroidViewModel {
private final UserHandle mUser;
@NonNull
+ private final LiveData<List<RoleApplicationItem>> mRecommendedLiveData;
+
+ @NonNull
private final LiveData<List<RoleApplicationItem>> mLiveData;
@NonNull
@@ -61,22 +66,34 @@ public class DefaultAppViewModel extends AndroidViewModel {
mUser = role.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP
? UserUtils.getProfileParentOrSelf(user, application)
: user;
- RoleLiveData liveData = new RoleLiveData(role, mUser, application);
+ RoleLiveData userLiveData = new RoleLiveData(role, mUser, application);
RoleSortFunction sortFunction = new RoleSortFunction(application);
+ LiveData<List<RoleApplicationItem>> liveData;
if (role.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP) {
// Context user might be work profile, ensure we get a non-null UserHandle if work
// profile exists. getWorkProfile returns null if context user is work profile.
UserHandle workProfile = UserUtils.getWorkProfileOrSelf(application);
if (workProfile != null) {
RoleLiveData workLiveData = new RoleLiveData(role, workProfile, application);
- mLiveData = Transformations.map(new MergeRoleLiveData(liveData, workLiveData),
+ liveData = Transformations.map(new MergeRoleLiveData(userLiveData, workLiveData),
sortFunction);
} else {
- mLiveData = Transformations.map(liveData, sortFunction);
+ liveData = Transformations.map(userLiveData, sortFunction);
}
} else {
- mLiveData = Transformations.map(liveData, sortFunction);
+ liveData = Transformations.map(userLiveData, sortFunction);
}
+ Predicate<RoleApplicationItem> recommendedApplicationFilter =
+ RoleUiBehaviorUtils.getRecommendedApplicationFilter(role, application);
+ mRecommendedLiveData = Transformations.map(liveData,
+ new ListLiveDataFilterFunction<>(recommendedApplicationFilter));
+ mLiveData = Transformations.map(liveData,
+ new ListLiveDataFilterFunction<>(recommendedApplicationFilter.negate()));
+ }
+
+ @NonNull
+ public LiveData<List<RoleApplicationItem>> getRecommendedLiveData() {
+ return mRecommendedLiveData;
}
@NonNull
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
index 4df3ccf99..c74c3d519 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
@@ -25,8 +25,15 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.permission.flags.Flags;
import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.role.ui.RoleApplicationItem;
import com.android.role.controller.model.Role;
+import com.android.role.controller.util.SignedPackage;
+import com.android.role.controller.util.SignedPackageUtils;
+
+import java.util.List;
+import java.util.function.Predicate;
/***
* Class for UI behavior of Assistant role
@@ -39,14 +46,26 @@ public class AssistantRoleUiBehavior implements RoleUiBehavior {
@NonNull Context context) {
boolean isAutomotive =
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
-
if (isAutomotive) {
return null;
}
-
return new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS);
}
+ @NonNull
+ @Override
+ public Predicate<RoleApplicationItem> getRecommendedApplicationFilter(
+ @NonNull Role role, @NonNull Context context) {
+ if (Flags.defaultAppsRecommendationEnabled()) {
+ List<SignedPackage> signedPackages = SignedPackage.parseList(
+ context.getResources().getString(R.string.config_recommendedAssistants));
+ return applicationItem -> SignedPackageUtils.matchesAny(
+ applicationItem.getApplicationInfo(), signedPackages, context);
+ } else {
+ return RoleUiBehavior.super.getRecommendedApplicationFilter(role, context);
+ }
+ }
+
@Nullable
@Override
public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
index ae5c03676..e1bf213a0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
@@ -26,10 +26,12 @@ import androidx.annotation.Nullable;
import androidx.preference.Preference;
import com.android.permissioncontroller.role.ui.RequestRoleItemView;
+import com.android.permissioncontroller.role.ui.RoleApplicationItem;
import com.android.permissioncontroller.role.ui.TwoTargetPreference;
import com.android.role.controller.model.Role;
import java.util.List;
+import java.util.function.Predicate;
/***
* Interface for UI behavior for roles
@@ -92,6 +94,20 @@ public interface RoleUiBehavior {
@NonNull UserHandle user, @NonNull Context context) {}
/**
+ * Get the filter for recommended applications of this role.
+ *
+ * @param role the role to get the recommended application filter for
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return the filter for recommended applications
+ */
+ @NonNull
+ default Predicate<RoleApplicationItem> getRecommendedApplicationFilter(
+ @NonNull Role role, @NonNull Context context) {
+ return applicationItem -> false;
+ }
+
+ /**
* Get the confirmation message for adding an application as a holder of this role.
*
* @param role the role to get confirmation message for
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
index c11a74259..255d88ff0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
@@ -26,12 +26,14 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.permissioncontroller.role.ui.RequestRoleItemView;
+import com.android.permissioncontroller.role.ui.RoleApplicationItem;
import com.android.permissioncontroller.role.ui.RoleApplicationPreference;
import com.android.permissioncontroller.role.ui.RolePreference;
import com.android.permissioncontroller.role.ui.behavior.RoleUiBehavior;
import com.android.role.controller.model.Role;
import java.util.List;
+import java.util.function.Predicate;
/**
* Utility methods for Role UI behavior
@@ -117,6 +119,19 @@ public final class RoleUiBehaviorUtils {
}
/**
+ * @see RoleUiBehavior#getRecommendedApplicationFilter
+ */
+ @NonNull
+ public static Predicate<RoleApplicationItem> getRecommendedApplicationFilter(
+ @NonNull Role role, @NonNull Context context) {
+ RoleUiBehavior uiBehavior = getUiBehavior(role);
+ if (uiBehavior == null) {
+ return applicationItem -> false;
+ }
+ return uiBehavior.getRecommendedApplicationFilter(role, context);
+ }
+
+ /**
* @see RoleUiBehavior#getConfirmationMessage
*/
@Nullable