diff options
author | 2025-02-05 16:04:43 -0800 | |
---|---|---|
committer | 2025-02-05 16:04:43 -0800 | |
commit | 709edc1e4b354717290d6234238e1c0478484e54 (patch) | |
tree | 04ef7eaabbc5ef9b67b5417258515d5d3703de40 /PermissionController/src | |
parent | 0eeed4de6203c5d90f9228ee55bdd8cddcb5e0b5 (diff) | |
parent | 9b11f01bc5fa240369136053641558ac89502ed9 (diff) |
Merge "Add recommended category for default app page" into main
Diffstat (limited to 'PermissionController/src')
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 |