diff options
author | 2025-02-04 10:43:25 -0800 | |
---|---|---|
committer | 2025-02-04 10:43:25 -0800 | |
commit | 2ed7c4c3e74acd854ff955afb684cfcb9b40963e (patch) | |
tree | a6498c58f0a50d7ba6cd65b5758b7dbabdd80090 | |
parent | 694f01b016f137012fe39740bb7804d5d9740e4f (diff) | |
parent | b25f034ab782e6bae168b1f8ee276206ef9fbdf8 (diff) |
Merge "Refactor default app implementation" into main
23 files changed, 616 insertions, 339 deletions
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java index 5109e505b..64682ba79 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java @@ -50,6 +50,7 @@ import com.android.role.controller.util.CollectionUtils; import com.android.role.controller.util.PackageUtils; import com.android.role.controller.util.RoleFlags; import com.android.role.controller.util.RoleManagerCompat; +import com.android.role.controller.util.SignedPackageUtils; import com.android.role.controller.util.UserUtils; import java.lang.annotation.Retention; @@ -84,10 +85,6 @@ public class Role { private static final String PACKAGE_NAME_ANDROID_SYSTEM = "android"; - private static final String DEFAULT_HOLDER_SEPARATOR = ";"; - - private static final String CERTIFICATE_SEPARATOR = ":"; - @Retention(RetentionPolicy.SOURCE) @IntDef({ EXCLUSIVITY_NONE, @@ -560,69 +557,11 @@ public class Role { } if (isExclusive()) { - String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolders, user, - context); - if (packageName == null) { - return Collections.emptyList(); - } - return Collections.singletonList(packageName); - } else { - List<String> packageNames = new ArrayList<>(); - for (String defaultHolder : defaultHolders.split(DEFAULT_HOLDER_SEPARATOR)) { - String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolder, - user, context); - if (packageName != null) { - packageNames.add(packageName); - } - } - return packageNames; - } - } - - @Nullable - private String getQualifiedDefaultHolderPackageNameAsUser(@NonNull String defaultHolder, - @NonNull UserHandle user, @NonNull Context context) { - String packageName; - byte[] certificate; - int certificateSeparatorIndex = defaultHolder.indexOf(CERTIFICATE_SEPARATOR); - if (certificateSeparatorIndex != -1) { - packageName = defaultHolder.substring(0, certificateSeparatorIndex); - String certificateString = defaultHolder.substring(certificateSeparatorIndex + 1); - try { - certificate = new Signature(certificateString).toByteArray(); - } catch (IllegalArgumentException e) { - Log.w(LOG_TAG, "Cannot parse signing certificate: " + defaultHolder, e); - return null; - } - } else { - packageName = defaultHolder; - certificate = null; - } - - if (certificate != null) { - Context userContext = UserUtils.getUserContext(context, user); - PackageManager userPackageManager = userContext.getPackageManager(); - if (!userPackageManager.hasSigningCertificate(packageName, certificate, - PackageManager.CERT_INPUT_SHA256)) { - Log.w(LOG_TAG, "Default holder doesn't have required signing certificate: " - + defaultHolder); - return null; - } + return CollectionUtils.singletonOrEmpty( + SignedPackageUtils.getPackageNameAsUser(defaultHolders, user, context)); } else { - ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - user, context); - if (applicationInfo == null) { - Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName); - return null; - } - if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - Log.w(LOG_TAG, "Default holder didn't specify a signing certificate and isn't a" - + " system app: " + packageName); - return null; - } + return SignedPackageUtils.getPackageNamesAsUser(defaultHolders, user, context); } - - return packageName; } /** diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java index cbffd451a..512015972 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java @@ -57,7 +57,7 @@ public final class PackageUtils { } /** - * Retrieve if a package is a system package. + * Check whether a package is a system package. * * @param packageName the name of the package * @param user the user of the package @@ -93,4 +93,22 @@ public final class PackageUtils { return null; } } + + /** + * Check whether a package has a signing certificate. + * + * @param packageName the name of the package + * @param certificate the signing certificate + * @param user the user of the package + * @param context the {@code Context} to retrieve system services + * + * @return whether the package has the signing certificate. + */ + public static boolean hasSigningCertificateAsUser(@NonNull String packageName, + @NonNull byte[] certificate, @NonNull UserHandle user, @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); + return userPackageManager.hasSigningCertificate(packageName, certificate, + PackageManager.CERT_INPUT_SHA256); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/SignedPackage.java b/PermissionController/role-controller/java/com/android/role/controller/util/SignedPackage.java new file mode 100644 index 000000000..a3869b349 --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/util/SignedPackage.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2025 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.role.controller.util; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A package name with an optional signing certificate. + */ +public class SignedPackage { + + private static final String LOG_TAG = SignedPackage.class.getSimpleName(); + + private static final String SIGNED_PACKAGE_SEPARATOR = ";"; + private static final String CERTIFICATE_SEPARATOR = ":"; + + /** + * The name of the package. + */ + @NonNull + private final String mPackageName; + + /** + * The signing certificate of the package. + */ + @Nullable + private final byte[] mCertificate; + + public SignedPackage(@NonNull String packageName, @Nullable byte[] certificate) { + mPackageName = packageName; + mCertificate = certificate; + } + + @NonNull + public String getPackageName() { + return mPackageName; + } + + @Nullable + public byte[] getCertificate() { + return mCertificate; + } + + /** + * Parse a {@link SignedPackage} from a string input. + * + * @param input the package name, optionally followed by a colon and a signing certificate + * digest if it's not a system app + * + * @return the parsed {@link SignedPackage}, or {@code null} if the input is invalid + */ + @Nullable + public static SignedPackage parse(@NonNull String input) { + String packageName; + byte[] certificate; + int certificateSeparatorIndex = input.indexOf(CERTIFICATE_SEPARATOR); + if (certificateSeparatorIndex != -1) { + packageName = input.substring(0, certificateSeparatorIndex); + String certificateString = input.substring(certificateSeparatorIndex + 1); + try { + certificate = new Signature(certificateString).toByteArray(); + } catch (IllegalArgumentException e) { + Log.w(LOG_TAG, "Cannot parse signing certificate: " + input, e); + return null; + } + } else { + packageName = input; + certificate = null; + } + return new SignedPackage(packageName, certificate); + } + + /** + * Parse a list of {@link SignedPackage}s from a string input. + * + * @param input the package names, each optionally followed by a colon and a signing certificate + * digest if it's not a system app + * + * @return the parsed list of valid {@link SignedPackage}s + */ + @NonNull + public static List<SignedPackage> parseList(@NonNull String input) { + if (TextUtils.isEmpty(input)) { + return Collections.emptyList(); + } + List<SignedPackage> signedPackages = new ArrayList<>(); + for (String signedPackageInput : input.split(SIGNED_PACKAGE_SEPARATOR)) { + SignedPackage signedPackage = parse(signedPackageInput); + if (signedPackage != null) { + signedPackages.add(signedPackage); + } + } + return signedPackages; + } + + /* + * Checks whether this signed package is available, i.e. it is installed, and either has the + * specified signing certificate or is a system app if no signing certificate is specified. + * + * @param user the user of the package + * @param context the {@code Context} to retrieve system services + * + * @return whether this signed package is available + */ + public boolean isAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) { + if (mCertificate != null) { + if (!PackageUtils.hasSigningCertificateAsUser(mPackageName, mCertificate, user, + context)) { + Log.w(LOG_TAG, "Package doesn't have required signing certificate: " + + mPackageName); + return false; + } + } else { + ApplicationInfo applicationInfo = + PackageUtils.getApplicationInfoAsUser(mPackageName, user, context); + if (applicationInfo == null) { + Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + mPackageName); + return false; + } + if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + Log.w(LOG_TAG, "Package didn't specify a signing certificate and isn't a" + + " system app: " + mPackageName); + return false; + } + } + return true; + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/SignedPackageUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/SignedPackageUtils.java new file mode 100644 index 000000000..817c31c5f --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/util/SignedPackageUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2025 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.role.controller.util; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.UserHandle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utility methods about {@link SignedPackage}. + */ +public final class SignedPackageUtils { + + private SignedPackageUtils() {} + + /** + * Get a list of package names from a string input for {@link SignedPackage}s. + * <p> + * This method only returns packages that are + * {@link SignedPackage#isAvailableAsUser(UserHandle, Context) available}. + * + * @param input the string input + * @param user the user of the packages + * @param context the {@code Context} to retrieve system services + * + * @return the package names + */ + @NonNull + public static List<String> getPackageNamesAsUser(@NonNull String input, + @NonNull UserHandle user, @NonNull Context context) { + List<SignedPackage> signedPackages = SignedPackage.parseList(input); + List<String> packageNames = new ArrayList<>(); + int signedPackagesSize = signedPackages.size(); + for (int i = 0; i < signedPackagesSize; i++) { + SignedPackage signedPackage = signedPackages.get(i); + if (signedPackage.isAvailableAsUser(user, context)) { + packageNames.add(signedPackage.getPackageName()); + } + } + return packageNames; + } + + /** + * Get a package name from a string input for a {@link SignedPackage}. + * <p> + * This method only returns a package if it is + * {@link SignedPackage#isAvailableAsUser(UserHandle, Context) available}. + * + * @param input the string input + * @param user the user of the package + * @param context the {@code Context} to retrieve system services + * + * @return the package name, or {@code null} otherwise + */ + @Nullable + public static String getPackageNameAsUser(@NonNull String input, @NonNull UserHandle user, + @NonNull Context context) { + SignedPackage signedPackage = SignedPackage.parse(input); + if (signedPackage == null || !signedPackage.isAvailableAsUser(user, context)) { + return null; + } + return signedPackage.getPackageName(); + } +} diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java index 61e33d10b..5f870b1e3 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java @@ -25,7 +25,6 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; import android.util.ArrayMap; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -34,6 +33,7 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; @@ -125,13 +125,17 @@ 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.getRoleLiveData().observe(this, this::onRoleChanged); + mViewModel.getLiveData().observe(this, applicationItems -> onApplicationListChanged()); mViewModel.getManageRoleHolderStateLiveData().observe(this, this::onManageRoleHolderStateChanged); } - private void onRoleChanged( - @NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) { + private void onApplicationListChanged() { + List<RoleApplicationItem> applicationItems = mViewModel.getLiveData().getValue(); + if (applicationItems == null) { + return; + } + PF preferenceFragment = requirePreferenceFragment(); PreferenceManager preferenceManager = preferenceFragment.getPreferenceManager(); Context context = preferenceManager.getContext(); @@ -142,37 +146,12 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat preferenceScreen = preferenceManager.createPreferenceScreen(context); preferenceFragment.setPreferenceScreen(preferenceScreen); } else { - for (int i = preferenceScreen.getPreferenceCount() - 1; i >= 0; --i) { - Preference preference = preferenceScreen.getPreference(i); - - preferenceScreen.removePreference(preference); - preference.setOrder(Preference.DEFAULT_ORDER); - oldPreferences.put(preference.getKey(), preference); - } + clearPreferences(preferenceScreen, oldPreferences); } - if (mRole.shouldShowNone()) { - Drawable icon = AppCompatResources.getDrawable(context, R.drawable.ic_remove_circle); - String title = getString(R.string.default_app_none); - boolean noHolderApplication = !hasHolderApplication(qualifyingApplications); - addPreference(PREFERENCE_KEY_NONE, icon, title, noHolderApplication, null, - oldPreferences, preferenceScreen, context); - } - - int qualifyingApplicationsSize = qualifyingApplications.size(); - for (int i = 0; i < qualifyingApplicationsSize; i++) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = qualifyingApplications.get(i); - ApplicationInfo qualifyingApplicationInfo = qualifyingApplication.first; - boolean isHolderApplication = qualifyingApplication.second; - - 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, - oldPreferences, preferenceScreen, context); - } + boolean noneChecked = !hasHolderApplication(applicationItems); + addNonePreferenceIfNeeded(preferenceScreen, noneChecked, oldPreferences, context); + addApplicationPreferences(preferenceScreen, applicationItems, oldPreferences, context); addNonPaymentNfcServicesPreference(preferenceScreen, oldPreferences, context); addDescriptionPreference(preferenceScreen, oldPreferences); @@ -180,24 +159,64 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat preferenceFragment.onPreferenceScreenChanged(); } - private static boolean hasHolderApplication( - @NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) { - int qualifyingApplicationsSize = qualifyingApplications.size(); - for (int i = 0; i < qualifyingApplicationsSize; i++) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = qualifyingApplications.get(i); - boolean isHolderApplication = qualifyingApplication.second; + private static void clearPreferences(@NonNull PreferenceGroup preferenceGroup, + @NonNull ArrayMap<String, Preference> oldPreferences) { + for (int i = preferenceGroup.getPreferenceCount() - 1; i >= 0; --i) { + Preference preference = preferenceGroup.getPreference(i); + + preferenceGroup.removePreference(preference); + preference.setOrder(Preference.DEFAULT_ORDER); + oldPreferences.put(preference.getKey(), preference); + } + } - if (isHolderApplication) { + private static boolean hasHolderApplication( + @NonNull List<RoleApplicationItem> applicationItems) { + int applicationItemsSize = applicationItems.size(); + for (int i = 0; i < applicationItemsSize; i++) { + RoleApplicationItem applicationItem = applicationItems.get(i); + if (applicationItem.isHolderApplication()) { return true; } } return false; } - private void addPreference(@NonNull String key, @NonNull Drawable icon, - @NonNull CharSequence title, boolean checked, @Nullable ApplicationInfo applicationInfo, - @NonNull ArrayMap<String, Preference> oldPreferences, - @NonNull PreferenceScreen preferenceScreen, @NonNull Context context) { + private void addNonePreferenceIfNeeded(@NonNull PreferenceGroup preferenceGroup, + boolean checked, @NonNull ArrayMap<String, Preference> oldPreferences, + @NonNull Context context) { + if (!mRole.shouldShowNone()) { + return; + } + + Drawable icon = AppCompatResources.getDrawable(context, R.drawable.ic_remove_circle); + String title = getString(R.string.default_app_none); + addApplicationPreference(preferenceGroup, PREFERENCE_KEY_NONE, icon, title, checked, null, + oldPreferences, context); + } + + private void addApplicationPreferences(@NonNull PreferenceGroup preferenceGroup, + @NonNull List<RoleApplicationItem> applicationItems, + @NonNull ArrayMap<String, Preference> oldPreferences, @NonNull Context context) { + int applicationItemsSize = applicationItems.size(); + for (int i = 0; i < applicationItemsSize; i++) { + RoleApplicationItem applicationItem = applicationItems.get(i); + ApplicationInfo applicationInfo = applicationItem.getApplicationInfo(); + int userId = UserHandle.getUserHandleForUid(applicationInfo.uid).getIdentifier(); + String key = applicationInfo.packageName + "@" + userId; + Drawable icon = Utils.getBadgedIcon(context, applicationInfo); + String title = Utils.getFullAppLabel(applicationInfo, context); + boolean isHolderApplication = applicationItem.isHolderApplication(); + + addApplicationPreference(preferenceGroup, key, icon, title, isHolderApplication, + applicationInfo, oldPreferences, context); + } + } + + private void addApplicationPreference(@NonNull PreferenceGroup preferenceGroup, + @NonNull String key, @NonNull Drawable icon, @NonNull CharSequence title, + boolean checked, @Nullable ApplicationInfo applicationInfo, + @NonNull ArrayMap<String, Preference> oldPreferences, @NonNull Context context) { RoleApplicationPreference roleApplicationPreference = (RoleApplicationPreference) oldPreferences.get(key); TwoStatePreference preference; @@ -233,7 +252,7 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat applicationInfo, user, context); } - preferenceScreen.addPreference(preference); + preferenceGroup.addPreference(preference); } private void onManageRoleHolderStateChanged(int state) { diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java index 48472bc5e..2a987167e 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java @@ -131,18 +131,16 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat } else { oldWorkPreferenceCategory = preferenceScreen.findPreference(PREFERENCE_KEY_WORK_CATEGORY); - clearPreferenceCategory( - oldWorkPreferenceCategory, preferenceScreen, oldWorkPreferences); + clearPreferenceCategory(oldWorkPreferenceCategory, oldWorkPreferences); oldPrivatePreferenceCategory = preferenceScreen.findPreference(PREFERENCE_KEY_PRIVATE_CATEGORY); - clearPreferenceCategory( - oldPrivatePreferenceCategory, preferenceScreen, oldPrivatePreferences); + clearPreferenceCategory(oldPrivatePreferenceCategory, oldPrivatePreferences); clearPreferences(preferenceScreen, oldPreferences); } - addPreferences(preferenceScreen, roleItems, oldPreferences, this, mViewModel.getUser(), + addRolePreferences(preferenceScreen, roleItems, oldPreferences, this, mViewModel.getUser(), context); addMoreDefaultAppsPreference(preferenceScreen, oldPreferences, context); addManageDomainUrlsPreference(preferenceScreen, oldPreferences, context); @@ -155,7 +153,7 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat } String workTitle = Utils.getEnterpriseString(context, DefaultAppSettings.WORK_PROFILE_DEFAULT_APPS_TITLE, defaultWorkTitle); - addPreferenceCategory(oldWorkPreferenceCategory, PREFERENCE_KEY_WORK_CATEGORY, + addRolePreferenceCategory(oldWorkPreferenceCategory, PREFERENCE_KEY_WORK_CATEGORY, workTitle, preferenceScreen, workRoleItems, oldWorkPreferences, this, mViewModel.getWorkProfile(), context); } @@ -166,22 +164,22 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat } else { privateTitle = context.getString(R.string.default_apps_for_private_profile); } - addPreferenceCategory(oldPrivatePreferenceCategory, PREFERENCE_KEY_PRIVATE_CATEGORY, - privateTitle, preferenceScreen, privateRoleItems, oldPrivatePreferences, this, - mViewModel.getPrivateProfile(), context); + addRolePreferenceCategory(oldPrivatePreferenceCategory, + PREFERENCE_KEY_PRIVATE_CATEGORY, privateTitle, preferenceScreen, + privateRoleItems, oldPrivatePreferences, this, mViewModel.getPrivateProfile(), + context); } preferenceFragment.onPreferenceScreenChanged(); } private static void clearPreferenceCategory(@Nullable PreferenceCategory preferenceCategory, - @NonNull PreferenceScreen preferenceScreen, @NonNull ArrayMap<String, Preference> oldPreferences) { if (preferenceCategory == null) { return; } clearPreferences(preferenceCategory, oldPreferences); - preferenceScreen.removePreference(preferenceCategory); + preferenceCategory.getParent().removePreference(preferenceCategory); preferenceCategory.setOrder(Preference.DEFAULT_ORDER); } @@ -197,7 +195,7 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat } @NonNull - private void addPreferenceCategory( + private void addRolePreferenceCategory( @Nullable PreferenceCategory oldPreferenceCategory, @NonNull String key, @Nullable String title, @NonNull PreferenceScreen preferenceScreen, @NonNull List<RoleItem> roleItems, @NonNull ArrayMap<String, Preference> oldPreferences, @@ -210,11 +208,10 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat preferenceCategory.setTitle(title); } preferenceScreen.addPreference(preferenceCategory); - addPreferences(preferenceCategory, roleItems, oldPreferences, listener, - user, context); + addRolePreferences(preferenceCategory, roleItems, oldPreferences, listener, user, context); } - private void addPreferences(@NonNull PreferenceGroup preferenceGroup, + private void addRolePreferences(@NonNull PreferenceGroup preferenceGroup, @NonNull List<RoleItem> roleItems, @NonNull ArrayMap<String, Preference> oldPreferences, @NonNull Preference.OnPreferenceClickListener listener, @NonNull UserHandle user, @NonNull Context context) { diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java index 718af090e..4a280bd58 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListViewModel.java @@ -78,11 +78,11 @@ public class DefaultAppListViewModel extends AndroidViewModel { mLiveData = Transformations.map( new MergeRoleListLiveData(liveData, Transformations.map(workLiveData, - new RoleListFilterFunction(exclusivityPredicate))), + new ListLiveDataFilterFunction<>(exclusivityPredicate))), sortFunction); mWorkLiveData = Transformations.map( Transformations.map(workLiveData, - new RoleListFilterFunction(exclusivityPredicate.negate())), + new ListLiveDataFilterFunction<>(exclusivityPredicate.negate())), sortFunction); } else if (Flags.crossUserRoleUxBugfixEnabled() && isWorkProfile) { // Show profile group exclusive roles from the profile parent (full user) in primary @@ -92,7 +92,7 @@ public class DefaultAppListViewModel extends AndroidViewModel { mLiveData = Transformations.map( new MergeRoleListLiveData(liveData, Transformations.map(profileParentLiveData, - new RoleListFilterFunction(exclusivityPredicate))), + new ListLiveDataFilterFunction<>(exclusivityPredicate))), sortFunction); mWorkLiveData = null; } else { diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java index cdee94b13..790c55d84 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java @@ -18,10 +18,8 @@ package com.android.permissioncontroller.role.ui; import android.app.Application; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.os.UserHandle; import android.util.Log; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; @@ -48,7 +46,7 @@ public class DefaultAppViewModel extends AndroidViewModel { private final UserHandle mUser; @NonNull - private final LiveData<List<Pair<ApplicationInfo, Boolean>>> mRoleLiveData; + private final LiveData<List<RoleApplicationItem>> mLiveData; @NonNull private final ManageRoleHolderStateLiveData mManageRoleHolderStateLiveData = @@ -60,30 +58,30 @@ public class DefaultAppViewModel extends AndroidViewModel { mRole = role; // If EXCLUSIVITY_PROFILE_GROUP this user should be profile parent - mUser = mRole.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP + mUser = role.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP ? UserUtils.getProfileParentOrSelf(user, application) : user; - RoleLiveData liveData = new RoleLiveData(mRole, mUser, application); + RoleLiveData liveData = new RoleLiveData(role, mUser, application); RoleSortFunction sortFunction = new RoleSortFunction(application); - if (mRole.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP) { + 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); - mRoleLiveData = Transformations.map(new MergeRoleLiveData(liveData, workLiveData), + mLiveData = Transformations.map(new MergeRoleLiveData(liveData, workLiveData), sortFunction); } else { - mRoleLiveData = Transformations.map(liveData, sortFunction); + mLiveData = Transformations.map(liveData, sortFunction); } } else { - mRoleLiveData = Transformations.map(liveData, sortFunction); + mLiveData = Transformations.map(liveData, sortFunction); } } @NonNull - public LiveData<List<Pair<ApplicationInfo, Boolean>>> getRoleLiveData() { - return mRoleLiveData; + public LiveData<List<RoleApplicationItem>> getLiveData() { + return mLiveData; } @NonNull diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListFilterFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/ListLiveDataFilterFunction.java index b84fa80b9..8657db0ab 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListFilterFunction.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/ListLiveDataFilterFunction.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.permissioncontroller.role.ui; import androidx.annotation.NonNull; @@ -25,29 +26,32 @@ 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. + * A function for + * {@link androidx.lifecycle.Transformations#map(androidx.lifecycle.LiveData, Function1)} + * that filters a live data for a list. + * + * @param <T> the type of the list elements */ -public class RoleListFilterFunction implements Function1<List<RoleItem>, List<RoleItem>> { - private final Predicate<RoleItem> mPredicate; +public class ListLiveDataFilterFunction<T> implements Function1<List<T>, List<T>> { + private final Predicate<T> mPredicate; - public RoleListFilterFunction(@NonNull Predicate<RoleItem> predicate) { + public ListLiveDataFilterFunction(@NonNull Predicate<T> 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); + public List<T> invoke(@Nullable List<T> items) { + List<T> filteredItems = new ArrayList<>(); + if (items != null) { + int itemsSize = items.size(); + for (int i = 0; i < itemsSize; i++) { + T item = items.get(i); + if (mPredicate.test(item)) { + filteredItems.add(item); } } } - return filteredRoleItems; + return filteredItems; } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/ListLiveDataSortFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/ListLiveDataSortFunction.java new file mode 100644 index 000000000..36e7afcc8 --- /dev/null +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/ListLiveDataSortFunction.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 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 kotlin.jvm.functions.Function1; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * A function for + * {@link androidx.lifecycle.Transformations#map(androidx.lifecycle.LiveData, Function1)} + * that sorts a live data for a list. + * + * @param <T> the type of the list elements + */ +public class ListLiveDataSortFunction<T> implements Function1<List<T>, List<T>> { + + @NonNull + private final Comparator<T> mComparator; + + public ListLiveDataSortFunction(@NonNull Comparator<T> comparator) { + mComparator = comparator; + } + + @Override + public List<T> invoke(List<T> items) { + List<T> sortedItems = new ArrayList<>(items); + sortedItems.sort(mComparator); + return sortedItems; + } +} diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java index 31a02729a..72c2264ce 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/MergeRoleLiveData.java @@ -16,9 +16,6 @@ package com.android.permissioncontroller.role.ui; -import android.content.pm.ApplicationInfo; -import android.util.Pair; - import androidx.annotation.NonNull; import androidx.lifecycle.MediatorLiveData; @@ -28,7 +25,7 @@ import java.util.List; /** * {@link MediatorLiveData} that merges multiple {@link RoleLiveData} instances. */ -public class MergeRoleLiveData extends MediatorLiveData<List<Pair<ApplicationInfo, Boolean>>> { +public class MergeRoleLiveData extends MediatorLiveData<List<RoleApplicationItem>> { @NonNull private final RoleLiveData[] mLiveDatas; @@ -40,23 +37,23 @@ public class MergeRoleLiveData extends MediatorLiveData<List<Pair<ApplicationInf for (int i = 0; i < liveDatasLength; i++) { RoleLiveData liveData = mLiveDatas[i]; - addSource(liveData, roleItems -> onRoleChanged()); + addSource(liveData, items -> onRoleChanged()); } } private void onRoleChanged() { - List<Pair<ApplicationInfo, Boolean>> mergedQualifyingApplications = new ArrayList<>(); + List<RoleApplicationItem> mergedItems = new ArrayList<>(); int liveDatasLength = mLiveDatas.length; for (int i = 0; i < liveDatasLength; i++) { RoleLiveData liveData = mLiveDatas[i]; - List<Pair<ApplicationInfo, Boolean>> qualifyingApplications = liveData.getValue(); - if (qualifyingApplications == null) { + List<RoleApplicationItem> items = liveData.getValue(); + if (items == null) { return; } - mergedQualifyingApplications.addAll(qualifyingApplications); + mergedItems.addAll(items); } - setValue(mergedQualifyingApplications); + setValue(mergedItems); } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java index 60139f0c8..f411b0cd0 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java @@ -30,7 +30,6 @@ import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; -import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -236,7 +235,7 @@ public class RequestRoleFragment extends DialogFragment { ViewModelProvider.Factory viewModelFactory = new RequestRoleViewModel.Factory(mRole, requireActivity().getApplication()); mViewModel = new ViewModelProvider(this, viewModelFactory).get(RequestRoleViewModel.class); - mViewModel.getRoleLiveData().observe(this, this::onRoleDataChanged); + mViewModel.getLiveData().observe(this, this::onApplicationListChanged); mViewModel.getManageRoleHolderStateLiveData().observe(this, this::onManageRoleHolderStateChanged); } @@ -272,9 +271,9 @@ public class RequestRoleFragment extends DialogFragment { setDeniedOnceAndFinish(); } - private void onRoleDataChanged( - @NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) { - mAdapter.replace(qualifyingApplications); + private void onApplicationListChanged( + @NonNull List<RoleApplicationItem> applicationItems) { + mAdapter.replace(applicationItems); updateUi(); } @@ -364,8 +363,8 @@ public class RequestRoleFragment extends DialogFragment { boolean dontAskAgain = mDontAskAgainCheck != null && mDontAskAgainCheck.isChecked(); mAdapter.setDontAskAgain(dontAskAgain); AlertDialog dialog = getDialog(); - boolean hasRoleData = mViewModel.getRoleLiveData().getValue() != null; - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled && hasRoleData + boolean hasApplicationList = mViewModel.getLiveData().getValue() != null; + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled && hasApplicationList && (dontAskAgain || !mAdapter.isHolderApplicationChecked())); dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(enabled); } @@ -420,12 +419,12 @@ public class RequestRoleFragment extends DialogFragment { } int count = mAdapter.getCount(); for (int i = 0; i < count; i++) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = mAdapter.getItem(i); - if (qualifyingApplication == null) { + RoleApplicationItem applicationItem = mAdapter.getItem(i); + if (applicationItem == null) { // Skip the "None" item. continue; } - ApplicationInfo applicationInfo = qualifyingApplication.first; + ApplicationInfo applicationInfo = applicationItem.getApplicationInfo(); if (Objects.equals(UserPackage.from(applicationInfo), userPackage)) { return applicationInfo.uid; } @@ -493,8 +492,7 @@ public class RequestRoleFragment extends DialogFragment { // We'll use a null to represent the "None" item. @NonNull - private final List<Pair<ApplicationInfo, Boolean>> mQualifyingApplications = - new ArrayList<>(); + private final List<RoleApplicationItem> mApplicationItems = new ArrayList<>(); @Nullable private UserPackage mHolderUserPackage; @@ -546,12 +544,12 @@ public class RequestRoleFragment extends DialogFragment { } public void onItemClicked(int position) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = getItem(position); - if (qualifyingApplication == null) { + RoleApplicationItem applicationItem = getItem(position); + if (applicationItem == null) { mUserChecked = true; mCheckedUserPackage = null; } else { - ApplicationInfo applicationInfo = qualifyingApplication.first; + ApplicationInfo applicationInfo = applicationItem.getApplicationInfo(); UserHandle user = UserHandle.getUserHandleForUid(applicationInfo.uid); Intent restrictionIntent = mRole.getApplicationRestrictionIntentAsUser( applicationInfo, user, mListView.getContext()); @@ -566,24 +564,24 @@ public class RequestRoleFragment extends DialogFragment { notifyDataSetChanged(); } - public void replace(@NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) { - mQualifyingApplications.clear(); + public void replace(@NonNull List<RoleApplicationItem> applicationItems) { + mApplicationItems.clear(); if (mRole.shouldShowNone()) { - mQualifyingApplications.add(0, null); + mApplicationItems.add(0, null); } - mQualifyingApplications.addAll(qualifyingApplications); - mHolderUserPackage = getHolderUserPackage(qualifyingApplications); + mApplicationItems.addAll(applicationItems); + mHolderUserPackage = getHolderUserPackage(applicationItems); if (mUserChecked && mCheckedUserPackage != null) { boolean isCheckedPackageNameFound = false; int count = getCount(); for (int i = 0; i < count; i++) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = getItem(i); - if (qualifyingApplication == null) { + RoleApplicationItem applicationItem = getItem(i); + if (applicationItem == null) { continue; } - ApplicationInfo applicationInfo = qualifyingApplication.first; - UserPackage userPackage = UserPackage.from(applicationInfo); + UserPackage userPackage = + UserPackage.from(applicationItem.getApplicationInfo()); if (Objects.equals(userPackage, mCheckedUserPackage)) { mUserChecked = true; @@ -606,19 +604,15 @@ public class RequestRoleFragment extends DialogFragment { @Nullable private static UserPackage getHolderUserPackage( - @NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) { - int qualifyingApplicationSize = qualifyingApplications.size(); - for (int i = 0; i < qualifyingApplicationSize; i++) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = qualifyingApplications.get( - i); - if (qualifyingApplication == null) { + @NonNull List<RoleApplicationItem> applicationItems) { + int applicationItemSize = applicationItems.size(); + for (int i = 0; i < applicationItemSize; i++) { + RoleApplicationItem applicationItem = applicationItems.get(i); + if (applicationItem == null) { continue; } - ApplicationInfo applicationInfo = qualifyingApplication.first; - boolean isHolderApplication = qualifyingApplication.second; - - if (isHolderApplication) { - return UserPackage.from(applicationInfo); + if (applicationItem.isHolderApplication()) { + return UserPackage.from(applicationItem.getApplicationInfo()); } } return null; @@ -645,13 +639,13 @@ public class RequestRoleFragment extends DialogFragment { @Override public int getCount() { - return mQualifyingApplications.size(); + return mApplicationItems.size(); } @Nullable @Override - public Pair<ApplicationInfo, Boolean> getItem(int position) { - return mQualifyingApplications.get(position); + public RoleApplicationItem getItem(int position) { + return mApplicationItems.get(position); } @Override @@ -660,9 +654,9 @@ public class RequestRoleFragment extends DialogFragment { // Work around AbsListView.confirmCheckedPositionsById() not respecting our count. return ListView.INVALID_ROW_ID; } - Pair<ApplicationInfo, Boolean> qualifyingApplication = getItem(position); - return qualifyingApplication == null ? 0 - : qualifyingApplication.first.packageName.hashCode(); + RoleApplicationItem applicationItem = getItem(position); + return applicationItem == null ? 0 + : applicationItem.getApplicationInfo().packageName.hashCode(); } @Override @@ -670,12 +664,11 @@ public class RequestRoleFragment extends DialogFragment { if (!mDontAskAgain) { return true; } - Pair<ApplicationInfo, Boolean> qualifyingApplication = getItem(position); - if (qualifyingApplication == null) { + RoleApplicationItem applicationItem = getItem(position); + if (applicationItem == null) { return mHolderUserPackage == null; } else { - boolean isHolderApplication = qualifyingApplication.second; - return isHolderApplication; + return applicationItem.isHolderApplication(); } } @@ -697,14 +690,14 @@ public class RequestRoleFragment extends DialogFragment { LAYOUT_TRANSITION_DURATION_MILLIS); } - Pair<ApplicationInfo, Boolean> qualifyingApplication = getItem(position); + RoleApplicationItem applicationItem = getItem(position); ApplicationInfo applicationInfo; boolean restricted; boolean checked; Drawable icon; String title; String subtitle; - if (qualifyingApplication == null) { + if (applicationItem == null) { applicationInfo = null; restricted = false; checked = mCheckedUserPackage == null; @@ -713,15 +706,14 @@ public class RequestRoleFragment extends DialogFragment { subtitle = mHolderUserPackage == null ? context.getString( R.string.request_role_current_default) : null; } else { - applicationInfo = qualifyingApplication.first; + applicationInfo = applicationItem.getApplicationInfo(); UserPackage userPackage = UserPackage.from(applicationInfo); restricted = mRole.getApplicationRestrictionIntentAsUser(applicationInfo, userPackage.user, context) != null; checked = Objects.equals(userPackage, mCheckedUserPackage); icon = Utils.getBadgedIcon(context, applicationInfo); title = Utils.getAppLabel(applicationInfo, context); - boolean isHolderApplication = qualifyingApplication.second; - subtitle = isHolderApplication + subtitle = applicationItem.isHolderApplication() ? context.getString(R.string.request_role_current_default) : checked ? context.getString(mRole.getRequestDescriptionResource()) : null; } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationItem.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationItem.java new file mode 100644 index 000000000..b6c489ea1 --- /dev/null +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationItem.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2025 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 android.content.pm.ApplicationInfo; + +import androidx.annotation.NonNull; + +/** + * Information about an application to be displayed in a list of applications qualifying for a role. + */ +public class RoleApplicationItem { + + /** + * The {@link ApplicationInfo} for this application. + */ + @NonNull + private final ApplicationInfo mApplicationInfo; + + /** + * Whether this application is holding the role. + */ + private final boolean mIsHolderApplication; + + public RoleApplicationItem(@NonNull ApplicationInfo applicationInfo, + boolean isHolderApplication) { + mApplicationInfo = applicationInfo; + mIsHolderApplication = isHolderApplication; + } + + @NonNull + public ApplicationInfo getApplicationInfo() { + return mApplicationInfo; + } + + public boolean isHolderApplication() { + return mIsHolderApplication; + } +} diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java index ca059aa32..07b4db1f4 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java @@ -23,30 +23,23 @@ import androidx.annotation.NonNull; import kotlin.jvm.functions.Function1; -import java.util.ArrayList; import java.util.Comparator; -import java.util.List; /** - * A function for {@link androidx.lifecycle#map(androidx.lifecycle.LiveData, Function1)} + * A function for + * {@link androidx.lifecycle.Transformations#map(androidx.lifecycle.LiveData, Function1)} * that sorts a live data for role list. */ -public class RoleListSortFunction implements Function1<List<RoleItem>, List<RoleItem>> { - - @NonNull - private final Comparator<RoleItem> mComparator; +public class RoleListSortFunction extends ListLiveDataSortFunction<RoleItem> { public RoleListSortFunction(@NonNull Context context) { - Collator collator = Collator.getInstance(context.getResources().getConfiguration() - .getLocales().get(0)); - mComparator = Comparator.comparing(roleItem -> context.getString( - roleItem.getRole().getShortLabelResource()), collator); + super(createComparator(context)); } - @Override - public List<RoleItem> invoke(List<RoleItem> p1) { - List<RoleItem> sorted = new ArrayList<>(p1); - sorted.sort(mComparator); - return sorted; + private static Comparator<RoleItem> createComparator(@NonNull Context context) { + Collator collator = Collator.getInstance(context.getResources().getConfiguration() + .getLocales().get(0)); + return Comparator.comparing(item -> context.getString( + item.getRole().getShortLabelResource()), collator); } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java index bb492f76d..1b6d42934 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.UserHandle; import android.util.Log; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; @@ -38,7 +37,7 @@ import java.util.List; /** * {@link LiveData} for a role. */ -public class RoleLiveData extends AsyncTaskLiveData<List<Pair<ApplicationInfo, Boolean>>> +public class RoleLiveData extends AsyncTaskLiveData<List<RoleApplicationItem>> implements OnRoleHoldersChangedListener { private static final String LOG_TAG = RoleLiveData.class.getSimpleName(); @@ -77,12 +76,12 @@ public class RoleLiveData extends AsyncTaskLiveData<List<Pair<ApplicationInfo, B @Override @WorkerThread - protected List<Pair<ApplicationInfo, Boolean>> loadValueInBackground() { + protected List<RoleApplicationItem> loadValueInBackground() { RoleManager roleManager = mContext.getSystemService(RoleManager.class); List<String> holderPackageNames = roleManager.getRoleHoldersAsUser(mRole.getName(), mUser); List<String> qualifyingPackageNames = mRole.getQualifyingPackagesAsUser(mUser, mContext); - List<Pair<ApplicationInfo, Boolean>> qualifyingApplications = new ArrayList<>(); + List<RoleApplicationItem> applicationItems = new ArrayList<>(); int qualifyingPackageNamesSize = qualifyingPackageNames.size(); for (int i = 0; i < qualifyingPackageNamesSize; i++) { String qualifyingPackageName = qualifyingPackageNames.get(i); @@ -98,9 +97,10 @@ public class RoleLiveData extends AsyncTaskLiveData<List<Pair<ApplicationInfo, B continue; } boolean isHolderApplication = holderPackageNames.contains(qualifyingPackageName); - qualifyingApplications.add(new Pair<>(qualifyingApplicationInfo, isHolderApplication)); + applicationItems.add( + new RoleApplicationItem(qualifyingApplicationInfo, isHolderApplication)); } - return qualifyingApplications; + return applicationItems; } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java index 10db9dbcd..9a06a6b01 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java @@ -17,10 +17,8 @@ package com.android.permissioncontroller.role.ui; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.icu.text.Collator; import android.os.UserHandle; -import android.util.Pair; import androidx.annotation.NonNull; @@ -28,34 +26,26 @@ import com.android.permissioncontroller.permission.utils.Utils; import kotlin.jvm.functions.Function1; -import java.util.ArrayList; import java.util.Comparator; -import java.util.List; /** - * A function for {@link androidx.lifecycle#map(androidx.lifecycle.LiveData, Function1)} + * A function for + * {@link androidx.lifecycle.Transformations#map(androidx.lifecycle.LiveData, Function1)} * that sorts a live data for role. */ -public class RoleSortFunction implements Function1<List<Pair<ApplicationInfo, Boolean>>, - List<Pair<ApplicationInfo, Boolean>>> { - - @NonNull - private final Comparator<Pair<ApplicationInfo, Boolean>> mComparator; +public class RoleSortFunction extends ListLiveDataSortFunction<RoleApplicationItem> { public RoleSortFunction(@NonNull Context context) { - Collator collator = Collator.getInstance(context.getResources().getConfiguration() - .getLocales().get(0)); - Comparator<Pair<ApplicationInfo, Boolean>> labelComparator = Comparator.comparing(role -> - Utils.getAppLabel(role.first, context), collator); - Comparator<Pair<ApplicationInfo, Boolean>> userIdComparator = Comparator.comparingInt(role - -> UserHandle.getUserHandleForUid(role.first.uid).getIdentifier()); - mComparator = labelComparator.thenComparing(userIdComparator); + super(createComparator(context)); } - @Override - public List<Pair<ApplicationInfo, Boolean>> invoke(List<Pair<ApplicationInfo, Boolean>> p1) { - List<Pair<ApplicationInfo, Boolean>> sorted = new ArrayList<>(p1); - sorted.sort(mComparator); - return sorted; + private static Comparator<RoleApplicationItem> createComparator(@NonNull Context context) { + Collator collator = Collator.getInstance(context.getResources().getConfiguration() + .getLocales().get(0)); + Comparator<RoleApplicationItem> labelComparator = Comparator.comparing(item -> + Utils.getAppLabel(item.getApplicationInfo(), context), collator); + Comparator<RoleApplicationItem> userIdComparator = Comparator.comparingInt(item + -> UserHandle.getUserHandleForUid(item.getApplicationInfo().uid).getIdentifier()); + return labelComparator.thenComparing(userIdComparator); } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java index 0963635e7..7a13eb2b5 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java @@ -23,7 +23,6 @@ import android.content.pm.ApplicationInfo; import android.os.Bundle; import android.os.UserHandle; import android.util.ArrayMap; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -37,6 +36,7 @@ import androidx.preference.TwoStatePreference; import com.android.permissioncontroller.permission.utils.Utils; import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData; +import com.android.permissioncontroller.role.ui.RoleApplicationItem; import com.android.permissioncontroller.role.ui.RoleApplicationPreference; import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils; import com.android.role.controller.model.Role; @@ -107,12 +107,12 @@ public class SpecialAppAccessChildFragment<PF extends PreferenceFragmentCompat activity.getApplication()); mViewModel = new ViewModelProvider(this, viewModelFactory) .get(SpecialAppAccessViewModel.class); - mViewModel.getRoleLiveData().observe(this, this::onRoleChanged); + mViewModel.getLiveData().observe(this, this::onApplicationListChanged); mViewModel.observeManageRoleHolderState(this, this::onManageRoleHolderStateChanged); } - private void onRoleChanged( - @NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) { + private void onApplicationListChanged( + @NonNull List<RoleApplicationItem> applicationItems) { PF preferenceFragment = requirePreferenceFragment(); PreferenceManager preferenceManager = preferenceFragment.getPreferenceManager(); Context context = preferenceManager.getContext(); @@ -138,14 +138,12 @@ public class SpecialAppAccessChildFragment<PF extends PreferenceFragmentCompat } } - int qualifyingApplicationsSize = qualifyingApplications.size(); - for (int i = 0; i < qualifyingApplicationsSize; i++) { - Pair<ApplicationInfo, Boolean> qualifyingApplication = qualifyingApplications.get(i); - ApplicationInfo qualifyingApplicationInfo = qualifyingApplication.first; - boolean isHolderPackage = qualifyingApplication.second; - - String key = qualifyingApplicationInfo.packageName + '_' - + qualifyingApplicationInfo.uid; + int applicationItemsSize = applicationItems.size(); + for (int i = 0; i < applicationItemsSize; i++) { + RoleApplicationItem applicationItem = applicationItems.get(i); + ApplicationInfo applicationInfo = applicationItem.getApplicationInfo(); + String key = applicationInfo.packageName + '_' + + applicationInfo.uid; RoleApplicationPreference roleApplicationPreference = (RoleApplicationPreference) oldPreferences.get(key); TwoStatePreference preference; @@ -153,24 +151,23 @@ public class SpecialAppAccessChildFragment<PF extends PreferenceFragmentCompat roleApplicationPreference = preferenceFragment.createApplicationPreference(); preference = roleApplicationPreference.asTwoStatePreference(); preference.setKey(key); - preference.setIcon(Utils.getBadgedIcon(context, qualifyingApplicationInfo)); - preference.setTitle(Utils.getFullAppLabel(qualifyingApplicationInfo, context)); + preference.setIcon(Utils.getBadgedIcon(context, applicationInfo)); + preference.setTitle(Utils.getFullAppLabel(applicationInfo, context)); preference.setPersistent(false); preference.setOnPreferenceChangeListener((preference2, newValue) -> false); preference.setOnPreferenceClickListener(this); preference.getExtras().putParcelable(PREFERENCE_EXTRA_APPLICATION_INFO, - qualifyingApplicationInfo); + applicationInfo); } else { preference = roleApplicationPreference.asTwoStatePreference(); } - preference.setChecked(isHolderPackage); - UserHandle user = UserHandle.getUserHandleForUid(qualifyingApplicationInfo.uid); + preference.setChecked(applicationItem.isHolderApplication()); + UserHandle user = UserHandle.getUserHandleForUid(applicationInfo.uid); roleApplicationPreference.setRestrictionIntent( - mRole.getApplicationRestrictionIntentAsUser(qualifyingApplicationInfo, user, - context)); + mRole.getApplicationRestrictionIntentAsUser(applicationInfo, user, context)); RoleUiBehaviorUtils.prepareApplicationPreferenceAsUser(mRole, roleApplicationPreference, - qualifyingApplicationInfo, user, context); + applicationInfo, user, context); preferenceScreen.addPreference(preference); } 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 c12265d43..f4abc0db1 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java @@ -17,12 +17,10 @@ package com.android.permissioncontroller.role.ui.specialappaccess; import android.app.Application; -import android.content.pm.ApplicationInfo; import android.os.Process; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; @@ -34,6 +32,7 @@ import androidx.lifecycle.ViewModelProvider; import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData; import com.android.permissioncontroller.role.ui.MergeRoleLiveData; +import com.android.permissioncontroller.role.ui.RoleApplicationItem; import com.android.permissioncontroller.role.ui.RoleLiveData; import com.android.permissioncontroller.role.ui.RoleSortFunction; import com.android.permissioncontroller.role.utils.UserUtils; @@ -52,7 +51,7 @@ public class SpecialAppAccessViewModel extends AndroidViewModel { private final Role mRole; @NonNull - private final LiveData<List<Pair<ApplicationInfo, Boolean>>> mRoleLiveData; + private final LiveData<List<RoleApplicationItem>> mLiveData; @NonNull private final ArrayMap<String, ManageRoleHolderStateLiveData> mManageRoleHolderStateLiveDatas = @@ -68,17 +67,17 @@ public class SpecialAppAccessViewModel extends AndroidViewModel { UserHandle workProfile = UserUtils.getWorkProfile(application); RoleSortFunction sortFunction = new RoleSortFunction(application); if (workProfile == null) { - mRoleLiveData = Transformations.map(roleLiveData, sortFunction); + mLiveData = Transformations.map(roleLiveData, sortFunction); } else { RoleLiveData workRoleLiveData = new RoleLiveData(role, workProfile, application); - mRoleLiveData = Transformations.map(new MergeRoleLiveData(roleLiveData, + mLiveData = Transformations.map(new MergeRoleLiveData(roleLiveData, workRoleLiveData), sortFunction); } } @NonNull - public LiveData<List<Pair<ApplicationInfo, Boolean>>> getRoleLiveData() { - return mRoleLiveData; + public LiveData<List<RoleApplicationItem>> getLiveData() { + return mLiveData; } /** 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 9e93f33c7..65548d9a1 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt @@ -17,12 +17,11 @@ package com.android.permissioncontroller.role.ui.wear import android.content.Context -import android.content.pm.ApplicationInfo import android.os.UserHandle -import android.util.Pair import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.utils.Utils import com.android.permissioncontroller.role.ui.DefaultAppViewModel +import com.android.permissioncontroller.role.ui.RoleApplicationItem import com.android.permissioncontroller.role.ui.wear.model.ConfirmDialogArgs import com.android.permissioncontroller.role.ui.wear.model.DefaultAppConfirmDialogViewModel import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils @@ -39,13 +38,13 @@ class WearDefaultAppHelper( fun getTitle() = context.getString(role.labelResource) fun getNonePreference( - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>> + applicationItems: List<RoleApplicationItem> ): WearRoleApplicationPreference? = if (role.shouldShowNone()) { WearRoleApplicationPreference( context = context, defaultLabel = context.getString(R.string.default_app_none), - checked = !hasHolderApplication(qualifyingApplications), + checked = !hasHolderApplication(applicationItems), onDefaultCheckChanged = { _ -> viewModel.setNoneDefaultApp() }, ) .apply { icon = context.getDrawable(R.drawable.ic_remove_circle) } @@ -54,12 +53,12 @@ class WearDefaultAppHelper( } fun getPreferences( - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>> + applicationItems: List<RoleApplicationItem> ): List<WearRoleApplicationPreference> { - return qualifyingApplications - .map { pair -> - val appInfo = pair.first - val selected = pair.second + return applicationItems + .map { applicationItem -> + val appInfo = applicationItem.applicationInfo + val selected = applicationItem.isHolderApplication val user = UserHandle.getUserHandleForUid(appInfo.uid) WearRoleApplicationPreference( context = context, @@ -127,7 +126,6 @@ class WearDefaultAppHelper( fun getDescription() = context.getString(role.descriptionResource) - private fun hasHolderApplication( - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>> - ): Boolean = qualifyingApplications.map { it.second }.contains(true) + private fun hasHolderApplication(applicationItems: List<RoleApplicationItem>): Boolean = + applicationItems.map { it.isHolderApplication }.contains(true) } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt index 067c5b1be..c3cbe4670 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt @@ -16,8 +16,6 @@ package com.android.permissioncontroller.role.ui.wear -import android.content.pm.ApplicationInfo -import android.util.Pair import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -25,6 +23,7 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import com.android.permissioncontroller.role.ui.RoleApplicationItem import com.android.permissioncontroller.role.ui.wear.model.ConfirmDialogArgs import com.android.permissioncontroller.wear.permission.components.ScrollableScreen import com.android.permissioncontroller.wear.permission.components.material3.DialogButtonContent @@ -39,7 +38,7 @@ import com.android.permissioncontroller.wear.permission.components.theme.WearPer @Composable fun WearDefaultAppScreen(helper: WearDefaultAppHelper) { - val roleLiveData = helper.viewModel.roleLiveData.observeAsState(emptyList()) + val roleLiveData = helper.viewModel.liveData.observeAsState(emptyList()) val showConfirmDialog = helper.confirmDialogViewModel.showConfirmDialogLiveData.observeAsState(false) var isLoading by remember { mutableStateOf(true) } @@ -60,11 +59,11 @@ fun WearDefaultAppScreen(helper: WearDefaultAppHelper) { @Composable private fun WearDefaultAppContent( isLoading: Boolean, - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>, + applicationItems: List<RoleApplicationItem>, helper: WearDefaultAppHelper, ) { ScrollableScreen(title = helper.getTitle(), isLoading = isLoading) { - helper.getNonePreference(qualifyingApplications)?.let { + helper.getNonePreference(applicationItems)?.let { item { WearPermissionToggleControl( label = it.title.toString(), @@ -76,7 +75,7 @@ private fun WearDefaultAppContent( ) } } - for (pref in helper.getPreferences(qualifyingApplications)) { + for (pref in helper.getPreferences(applicationItems)) { item { WearPermissionToggleControl( label = pref.title.toString(), diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt index af8dc5e92..99f2fe36f 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt @@ -231,11 +231,11 @@ class WearRequestRoleFragment : Fragment() { if (userPackage == null) { return -1 } - viewModel.roleLiveData.value?.let { qualifyingApplications -> - for (qualifyingApplication in qualifyingApplications) { - val qualifyingApplicationInfo = qualifyingApplication.first - val qualifyingAppUserPackage = UserPackage.from(qualifyingApplicationInfo) - if (Objects.equals(qualifyingAppUserPackage, userPackage)) { + viewModel.liveData.value?.let { applicationItems -> + for (applicationItem in applicationItems) { + val qualifyingApplicationInfo = applicationItem.applicationInfo + val qualifyingUserPackage = UserPackage.from(qualifyingApplicationInfo) + if (Objects.equals(qualifyingUserPackage, userPackage)) { return qualifyingApplicationInfo.uid } } @@ -244,12 +244,10 @@ class WearRequestRoleFragment : Fragment() { } private fun getHolderUserPackage(): UserPackage? { - viewModel.roleLiveData.value?.let { qualifyingApplications -> + viewModel.liveData.value?.let { qualifyingApplications -> for (qualifyingApplication in qualifyingApplications) { - val isHolderApplication = qualifyingApplication.second - if (isHolderApplication) { - val applicationInfo = qualifyingApplication.first - return UserPackage.from(applicationInfo) + if (qualifyingApplication.isHolderApplication) { + return UserPackage.from(qualifyingApplication.applicationInfo) } } } @@ -257,7 +255,7 @@ class WearRequestRoleFragment : Fragment() { } private fun getQualifyingApplicationCount(): Int { - return viewModel.roleLiveData.value?.size ?: -1 + return viewModel.liveData.value?.size ?: -1 } private fun setDeniedAlwaysAndFinish() { diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt index f8a1b1ee8..f95f1ee90 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt @@ -20,12 +20,12 @@ import android.content.Context import android.content.pm.ApplicationInfo import android.graphics.drawable.Drawable import android.os.Process -import android.util.Pair import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.utils.Utils import com.android.permissioncontroller.role.UserPackage import com.android.permissioncontroller.role.model.UserDeniedManager import com.android.permissioncontroller.role.ui.RequestRoleViewModel +import com.android.permissioncontroller.role.ui.RoleApplicationItem import com.android.permissioncontroller.role.ui.wear.model.WearRequestRoleViewModel import com.android.role.controller.model.Role import java.util.Objects @@ -50,11 +50,11 @@ class WearRequestRoleHelper( UserDeniedManager.getInstance(context).isDeniedOnce(roleName, packageName) fun getNonePreference( - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>, + applicationItems: List<RoleApplicationItem>, selectedPackage: UserPackage?, ): RequestRolePreference? = if (role.shouldShowNone()) { - val hasHolderApplication = hasHolderApplication(qualifyingApplications) + val hasHolderApplication = hasHolderApplication(applicationItems) RequestRolePreference( userPackage = null, label = context.getString(R.string.default_app_none), @@ -79,48 +79,47 @@ class WearRequestRoleHelper( } fun getPreferences( - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>, + applicationItems: List<RoleApplicationItem>, selectedPackage: UserPackage?, ): List<RequestRolePreference> { - return qualifyingApplications - .map { qualifyingApplication -> - val userPackage = UserPackage.from(qualifyingApplication.first) + return applicationItems + .map { applicationItem -> + val userPackage = UserPackage.from(applicationItem.applicationInfo) RequestRolePreference( userPackage = userPackage, - label = Utils.getAppLabel(qualifyingApplication.first, context), + label = Utils.getAppLabel(applicationItem.applicationInfo, context), subTitle = - if (qualifyingApplication.second) { + if (applicationItem.isHolderApplication) { context.getString(R.string.request_role_current_default) } else { context.getString(role.requestDescriptionResource) }, - icon = Utils.getBadgedIcon(context, qualifyingApplication.first), + icon = Utils.getBadgedIcon(context, applicationItem.applicationInfo), checked = Objects.equals(userPackage, selectedPackage), enabled = if (!wearViewModel.dontAskAgain()) { true } else { - qualifyingApplication.second + applicationItem.isHolderApplication }, - isHolder = qualifyingApplication.second, + isHolder = applicationItem.isHolderApplication, ) } .toList() } - private fun hasHolderApplication( - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>> - ): Boolean = qualifyingApplications.map { it.second }.contains(true) + private fun hasHolderApplication(applicationItems: List<RoleApplicationItem>): Boolean = + applicationItems.map { it.isHolderApplication }.contains(true) fun shouldSetAsDefaultEnabled(enabled: Boolean): Boolean { return enabled && (wearViewModel.dontAskAgain() || !wearViewModel.isHolderChecked) } - fun initializeHolderPackage(qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>) { + fun initializeHolderPackage(applicationItems: List<RoleApplicationItem>) { wearViewModel.holderPackage = - qualifyingApplications - .find { it.second } - ?.first + applicationItems + .find { it.isHolderApplication } + ?.applicationInfo ?.let { appInfo -> UserPackage.from(appInfo) } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt index 5244e1a63..1367f4c3c 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt @@ -16,8 +16,6 @@ package com.android.permissioncontroller.role.ui.wear -import android.content.pm.ApplicationInfo -import android.util.Pair import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable @@ -33,6 +31,7 @@ import androidx.compose.ui.unit.dp import com.android.permissioncontroller.R import com.android.permissioncontroller.role.UserPackage import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData +import com.android.permissioncontroller.role.ui.RoleApplicationItem import com.android.permissioncontroller.wear.permission.components.ScrollableScreen import com.android.permissioncontroller.wear.permission.components.material3.WearPermissionButton import com.android.permissioncontroller.wear.permission.components.material3.WearPermissionButtonStyle @@ -50,7 +49,7 @@ fun WearRequestRoleScreen( onSetAsDefault: (Boolean, UserPackage?) -> Unit, onCanceled: () -> Unit, ) { - val roleLiveData = helper.viewModel.roleLiveData.observeAsState(emptyList()) + val roleLiveData = helper.viewModel.liveData.observeAsState(emptyList()) val manageRoleHolderState = helper.viewModel.manageRoleHolderStateLiveData.observeAsState( ManageRoleHolderStateLiveData.STATE_WORKING @@ -102,7 +101,7 @@ internal fun WearRequestRoleContent( materialUIVersion: WearPermissionMaterialUIVersion, isLoading: Boolean, helper: WearRequestRoleHelper, - qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>, + applicationItems: List<RoleApplicationItem>, enabled: Boolean, dontAskAgain: Boolean, selectedPackage: UserPackage?, @@ -118,7 +117,7 @@ internal fun WearRequestRoleContent( showTimeText = false, isLoading = isLoading, ) { - helper.getNonePreference(qualifyingApplications, selectedPackage)?.let { pref -> + helper.getNonePreference(applicationItems, selectedPackage)?.let { pref -> item { WearPermissionToggleControl( materialUIVersion = materialUIVersion, @@ -143,7 +142,7 @@ internal fun WearRequestRoleContent( } } - for (pref in helper.getPreferences(qualifyingApplications, selectedPackage)) { + for (pref in helper.getPreferences(applicationItems, selectedPackage)) { item { WearPermissionToggleControl( materialUIVersion = materialUIVersion, |