summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Omer Ozer <omerozer@google.com> 2023-07-27 21:07:06 +0000
committer Omer Ozer <omerozer@google.com> 2024-01-09 19:04:03 +0000
commit074084c44439edb39d572d6ff1e8ed3a845d534a (patch)
tree72c86cb191e1919c461000d9b1d362d009901ce1
parent4cb1f85cecd7c30b45bebf521e1d239a52ec4015 (diff)
Create a new default wallet role entry.
Bug: 283989236 Bug: 291794775 Test: local testing Change-Id: Ibd1b48e62b2702678434add5a007ca24d9fbf7d2
-rw-r--r--PermissionController/AndroidManifest.xml13
-rw-r--r--PermissionController/res/values/strings.xml9
-rw-r--r--PermissionController/res/xml/roles.xml18
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java129
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java76
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java187
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java8
-rw-r--r--framework-s/api/current.txt1
-rw-r--r--framework-s/java/android/app/role/RoleManager.java9
14 files changed, 460 insertions, 6 deletions
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml
index 379f7bd68..6dfee27d0 100644
--- a/PermissionController/AndroidManifest.xml
+++ b/PermissionController/AndroidManifest.xml
@@ -66,6 +66,7 @@
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
<uses-permission android:name="android.permission.READ_APP_SPECIFIC_LOCALES" />
<uses-permission android:name="android.permission.GET_APP_METADATA" />
+ <uses-permission android:name="android.permission.NFC_PREFERRED_PAYMENT_INFO" />
<application android:name="com.android.permissioncontroller.PermissionControllerApplication"
android:label="@string/app_name"
@@ -472,6 +473,18 @@
</intent-filter>
</activity>
+ <activity android:name="com.android.permissioncontroller.role.ui.ChangeDefaultCardEmulationActivity"
+ android:enabled="@bool/is_at_least_v"
+ android:excludeFromRecents="true"
+ android:noHistory="true"
+ android:exported="true"
+ android:theme="@android:style/Theme.NoDisplay">
+ <intent-filter android:priority="1001">
+ <action android:name="android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<provider android:name="com.android.permissioncontroller.permission.service.PermissionSearchIndexablesProvider"
android:authorities="com.android.permissioncontroller"
android:multiprocess="false"
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index 24db04f2d..5e1c7d162 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -1223,6 +1223,15 @@
<!-- Search keywords for the NOTES role. [CHAR LIMIT=NONE] -->
<string name="role_notes_search_keywords">notes</string>
+ <!-- Label for the wallet role. [CHAR LIMIT=30] -->
+ <string name="role_wallet_label">Default wallet app</string>
+ <!-- Short label for the wallet role. [CHAR LIMIT=30] -->
+ <string name="role_wallet_short_label">Wallet app</string>
+ <!-- Description for the wallet role. [CHAR LIMIT=NONE] -->
+ <string name="role_wallet_description">Wallet apps can store your credit and loyalty cards, car keys and other things to help with various forms of transactions.</string>
+ <string name="role_wallet_request_title">Set <xliff:g id="app_name" example="Super Wallet">%1$s</xliff:g> as your default wallet app?</string>
+ <string name="role_wallet_request_description">No permissions needed</string>
+
<!-- Subtitle for the application that is the current default application [CHAR LIMIT=30] -->
<string name="request_role_current_default">Current default</string>
diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml
index e8f838c81..f09056f73 100644
--- a/PermissionController/res/xml/roles.xml
+++ b/PermissionController/res/xml/roles.xml
@@ -1655,4 +1655,22 @@
<app-op-permission name="android.permission.PACKAGE_USAGE_STATS" />
</app-op-permissions>
</role>
+
+ <role
+ name="android.app.role.WALLET"
+ behavior="WalletRoleBehavior"
+ defaultHolders="config_defaultWallet"
+ description="@string/role_wallet_description"
+ exclusive="true"
+ label="@string/role_wallet_label"
+ minSdkVersion="35"
+ overrideUserWhenGranting="true"
+ requestable="true"
+ requestDescription="@string/role_wallet_request_description"
+ requestTitle="@string/role_wallet_request_title"
+ showNone="true"
+ shortLabel="@string/role_wallet_short_label"
+ uiBehavior="WalletRoleUiBehavior"/>
+
+
</roles>
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java
new file mode 100644
index 000000000..170c42c3d
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 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.behavior;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.nfc.NfcAdapter;
+import android.nfc.cardemulation.ApduServiceInfo;
+import android.nfc.cardemulation.CardEmulation;
+import android.nfc.cardemulation.HostApduService;
+import android.nfc.cardemulation.OffHostApduService;
+import android.os.Build;
+import android.os.UserHandle;
+import android.permission.flags.Flags;
+import android.service.quickaccesswallet.QuickAccessWalletService;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.UserUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Handles the behavior of the wallet role.
+ */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+public class WalletRoleBehavior implements RoleBehavior {
+
+ private static final String LOG_TAG = WalletRoleBehavior.class.getSimpleName();
+
+ @Override
+ public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return SdkLevel.isAtLeastV() && Flags.walletRoleEnabled()
+ && !UserUtils.isProfile(user, context);
+ }
+
+ @Nullable
+ @Override
+ public List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ CardEmulation cardEmulation;
+ Context userContext = UserUtils.getUserContext(context, user);
+ try {
+ cardEmulation =
+ CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(userContext));
+ } catch (UnsupportedOperationException e) {
+ Log.e(LOG_TAG, "Unsupported Card Emulation Operation.", e);
+ return null;
+ }
+ ApduServiceInfo preferredPaymentService = cardEmulation
+ .getPreferredPaymentService();
+ if (preferredPaymentService != null) {
+ return Collections.singletonList(preferredPaymentService.getComponent()
+ .getPackageName());
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return !getQualifyingPackageNamesInternal(packageName, user, context).isEmpty();
+ }
+
+ @Nullable
+ @Override
+ public List<String> getQualifyingPackagesAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return new ArrayList<>(getQualifyingPackageNamesInternal(null, user, context));
+ }
+
+ @NonNull
+ private static Set<String> getQualifyingPackageNamesInternal(@Nullable String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Set<String> packageNames =
+ resolvePackageNames(HostApduService.SERVICE_INTERFACE, packageName, user,
+ context);
+ packageNames.addAll(
+ resolvePackageNames(OffHostApduService.SERVICE_INTERFACE, packageName, user,
+ context));
+ packageNames.addAll(
+ resolvePackageNames(QuickAccessWalletService.SERVICE_INTERFACE, packageName, user,
+ context));
+ return packageNames;
+ }
+
+ @NonNull
+ private static Set<String> resolvePackageNames(@NonNull String action,
+ @Nullable String packageName, @NonNull UserHandle user, @NonNull Context context) {
+ Intent intent = new Intent(action).setPackage(packageName);
+ PackageManager packageManager = context.getPackageManager();
+ List<ResolveInfo> resolveInfos = packageManager
+ .queryIntentServicesAsUser(intent, 0, user);
+ Set<String> packageNames = new ArraySet<>();
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ packageNames.add(resolveInfos.get(i).serviceInfo.packageName);
+ }
+ return packageNames;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java
new file mode 100644
index 000000000..882d01c56
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.app.Activity;
+import android.app.role.RoleManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+import android.os.Process;
+import android.permission.flags.Flags;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Activity to handle {@link android.nfc.cardemulation.CardEmulation#ACTION_CHANGE_DEFAULT}.
+ */
+public class ChangeDefaultCardEmulationActivity extends Activity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent;
+ if (SdkLevel.isAtLeastV() && Flags.walletRoleEnabled()) {
+ intent = DefaultAppActivity.createIntent(RoleManager.ROLE_WALLET,
+ Process.myUserHandle(), this);
+ } else {
+ intent = getIntent();
+ setDefaultPaymentChangeHandlerDialogComponent(intent);
+ }
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ finish();
+ }
+
+ // The only other handler of this intent is in the NFC stack.
+ private void setDefaultPaymentChangeHandlerDialogComponent(@NonNull Intent intent) {
+ Intent queryIntent = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
+ PackageManager packageManager = getPackageManager();
+ List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(queryIntent,
+ PackageManager.MATCH_SYSTEM_ONLY);
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ String packageName = resolveInfo.activityInfo.packageName;
+ if (!Objects.equals(packageName, getPackageName())) {
+ intent.setClassName(packageName,
+ resolveInfo.activityInfo.name);
+ return;
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
index f9a0193bd..e68fa88a0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
@@ -191,7 +191,8 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat
preference.setIcon(Utils.getBadgedIcon(context, holderApplicationInfo));
preference.setSummary(Utils.getAppLabel(holderApplicationInfo, context));
}
- RoleUiBehaviorUtils.preparePreferenceAsUser(role, rolePreference, user, context);
+ RoleUiBehaviorUtils.preparePreferenceAsUser(role, holderApplicationInfos,
+ rolePreference, user, context);
preferenceGroup.addPreference(preference);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
index 323325d0b..0142e1c40 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
@@ -38,6 +38,8 @@ import com.android.permissioncontroller.role.ui.TwoTargetPreference;
import com.android.permissioncontroller.role.utils.UserUtils;
import com.android.role.controller.model.Role;
+import java.util.List;
+
/***
* Class for UI behavior of Home role
*/
@@ -47,7 +49,8 @@ public class HomeRoleUiBehavior implements RoleUiBehavior {
@Override
public void preparePreferenceAsUser(@NonNull Role role, @NonNull TwoTargetPreference preference,
- @NonNull UserHandle user, @NonNull Context context) {
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
TwoTargetPreference.OnSecondTargetClickListener listener = null;
RoleManager roleManager = context.getSystemService(RoleManager.class);
String packageName = CollectionUtils.firstOrNull(roleManager.getRoleHoldersAsUser(
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 29dc5d2fc..0a8f9113f 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
@@ -28,6 +28,8 @@ import androidx.preference.Preference;
import com.android.permissioncontroller.role.ui.TwoTargetPreference;
import com.android.role.controller.model.Role;
+import java.util.List;
+
/***
* Interface for UI behavior for roles
*/
@@ -53,11 +55,13 @@ public interface RoleUiBehavior {
*
* @param role the role to prepare the preference for
* @param preference the {@link Preference} for this role
+ * @param applicationInfos a list {@link ApplicationInfo} for the current role holders
* @param user the user for this role
* @param context the {@code Context} to retrieve system services
*/
default void preparePreferenceAsUser(@NonNull Role role,
@NonNull TwoTargetPreference preference,
+ @NonNull List<ApplicationInfo> applicationInfos,
@NonNull UserHandle user,
@NonNull Context context) {}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java
new file mode 100644
index 000000000..858621d74
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 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.behavior;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.nfc.cardemulation.ApduServiceInfo;
+import android.nfc.cardemulation.CardEmulation;
+import android.nfc.cardemulation.HostApduService;
+import android.nfc.cardemulation.OffHostApduService;
+import android.os.Build;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.util.Pair;
+import androidx.preference.Preference;
+
+import com.android.permissioncontroller.role.ui.TwoTargetPreference;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.util.UserUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/***
+ * Class for UI behavior of Wallet role
+ */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+public class WalletRoleUiBehavior implements RoleUiBehavior {
+
+ private static final String LOG_TAG = WalletRoleUiBehavior.class.getSimpleName();
+
+ @Override
+ public void preparePreferenceAsUser(@NonNull Role role, @NonNull TwoTargetPreference preference,
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ if (!applicationInfos.isEmpty()) {
+ preparePreferenceInternal(preference.asPreference(), applicationInfos.get(0),
+ false, user, userContext);
+ }
+ }
+
+ @Override
+ public void prepareApplicationPreferenceAsUser(@NonNull Role role,
+ @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ preparePreferenceInternal(preference, applicationInfo, true, user, userContext);
+ }
+
+ private void preparePreferenceInternal(@NonNull Preference preference,
+ @NonNull ApplicationInfo applicationInfo, boolean setTitle, @NonNull UserHandle user,
+ @NonNull Context context) {
+ if (isSystemApplication(applicationInfo)) {
+ List<ApduServiceInfo> serviceInfos = getNfcServicesForPackage(
+ applicationInfo.packageName, user, context);
+
+ Pair<Drawable, CharSequence> bannerAndLabel =
+ getNonPaymentServiceBannerAndLabelIfExists(serviceInfos, user, context);
+ if (bannerAndLabel != null) {
+ preference.setIcon(bannerAndLabel.first);
+ if (setTitle) {
+ preference.setTitle(bannerAndLabel.second);
+ } else {
+ preference.setSummary(bannerAndLabel.second);
+ }
+ }
+ }
+ }
+
+ @NonNull
+ private static List<ApduServiceInfo> getNfcServicesForPackage(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ Intent hostApduIntent = new Intent(HostApduService.SERVICE_INTERFACE);
+ Intent offHostApduIntent = new Intent(OffHostApduService.SERVICE_INTERFACE);
+ hostApduIntent.setPackage(packageName);
+ offHostApduIntent.setPackage(packageName);
+ List<ResolveInfo> hostApduServices = packageManager.queryIntentServicesAsUser(
+ hostApduIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), user);
+ List<ResolveInfo> offHostApduServices = packageManager.queryIntentServicesAsUser(
+ offHostApduIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), user);
+ List<ApduServiceInfo> nfcServices = new ArrayList<>();
+ int apduServiceInfoSize = hostApduServices.size();
+ for (int i = 0; i < apduServiceInfoSize; i++) {
+ ResolveInfo resolveInfo = hostApduServices.get(i);
+ ApduServiceInfo apduServiceInfo;
+ try {
+ apduServiceInfo = new ApduServiceInfo(packageManager, resolveInfo, true);
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(LOG_TAG, "Error creating the apduserviceinfo.", e);
+ continue;
+ }
+ nfcServices.add(apduServiceInfo);
+ }
+ int offHostApduServiceInfoSize = offHostApduServices.size();
+ for (int i = 0; i < offHostApduServiceInfoSize; i++) {
+ ResolveInfo resolveInfo = offHostApduServices.get(i);
+ ApduServiceInfo apduServiceInfo;
+ try {
+ apduServiceInfo = new ApduServiceInfo(packageManager, resolveInfo, false);
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(LOG_TAG, "Error creating the apduserviceinfo.", e);
+ continue;
+ }
+ nfcServices.add(apduServiceInfo);
+ }
+ return nfcServices;
+ }
+
+ @Nullable
+ private Pair<Drawable, CharSequence> getNonPaymentServiceBannerAndLabelIfExists(
+ @NonNull List<ApduServiceInfo> apduServiceInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
+ Pair<Drawable, CharSequence> bannerAndLabel;
+ int apduServiceInfoSize = apduServiceInfos.size();
+ for (int i = 0; i < apduServiceInfoSize; i++) {
+ ApduServiceInfo serviceInfo = apduServiceInfos.get(i);
+ if (serviceInfo.getAids().isEmpty()) {
+ bannerAndLabel = loadBannerAndLabel(serviceInfo, userPackageManager);
+ if (bannerAndLabel != null) {
+ return bannerAndLabel;
+ }
+ } else {
+ List<String> aids = serviceInfo.getAids();
+ int aidsSize = aids.size();
+ for (int j = 0; j < aidsSize; j++) {
+ String aid = aids.get(j);
+ String category = serviceInfo.getCategoryForAid(aid);
+ if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) {
+ bannerAndLabel = loadBannerAndLabel(serviceInfo, userPackageManager);
+ if (bannerAndLabel != null) {
+ return bannerAndLabel;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private Pair<Drawable, CharSequence> loadBannerAndLabel(@NonNull ApduServiceInfo info,
+ @NonNull PackageManager userPackageManager) {
+ Drawable drawable = info.loadBanner(userPackageManager);
+ CharSequence label = info.loadLabel(userPackageManager);
+ if (drawable != null && !TextUtils.isEmpty(label)) {
+ return new Pair<>(drawable, label);
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean isSystemApplication(@NonNull ApplicationInfo applicationInfo) {
+ return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
index 4b256cef0..b06904930 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
@@ -115,7 +115,8 @@ public class SpecialAppAccessListChildFragment<PF extends PreferenceFragmentComp
} else {
preference = rolePreference.asPreference();
}
- RoleUiBehaviorUtils.preparePreferenceAsUser(role, rolePreference,
+ RoleUiBehaviorUtils.preparePreferenceAsUser(role, roleItem.getHolderApplicationInfos(),
+ rolePreference,
Process.myUserHandle(),
context);
preferenceScreen.addPreference(preference);
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt
index 5e8a2f9ad..bbcedea53 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt
@@ -61,6 +61,7 @@ class WearDefaultAppListHelper(val context: Context, val user: UserHandle) {
.let {
RoleUiBehaviorUtils.preparePreferenceAsUser(
roleItem.role,
+ roleItem.holderApplicationInfos,
it,
user,
context
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
index 7ebc1ebd1..5114af536 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
@@ -33,6 +33,8 @@ import com.android.permissioncontroller.role.ui.UserRestrictionAwarePreference;
import com.android.permissioncontroller.role.ui.behavior.RoleUiBehavior;
import com.android.role.controller.model.Role;
+import java.util.List;
+
/**
* Utility methods for Role UI behavior
*/
@@ -78,15 +80,15 @@ public final class RoleUiBehaviorUtils {
* @see RoleUiBehavior#preparePreferenceAsUser
*/
public static void preparePreferenceAsUser(@NonNull Role role,
- @NonNull RolePreference preference, @NonNull UserHandle user,
- @NonNull Context context) {
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull RolePreference preference,
+ @NonNull UserHandle user, @NonNull Context context) {
prepareUserRestrictionAwarePreferenceAsUser(role, preference, user, context);
RoleUiBehavior uiBehavior = getUiBehavior(role);
if (uiBehavior == null) {
return;
}
- uiBehavior.preparePreferenceAsUser(role, preference, user, context);
+ uiBehavior.preparePreferenceAsUser(role, preference, applicationInfos, user, context);
}
/**
diff --git a/framework-s/api/current.txt b/framework-s/api/current.txt
index d54af92f5..d943a03a1 100644
--- a/framework-s/api/current.txt
+++ b/framework-s/api/current.txt
@@ -14,6 +14,7 @@ package android.app.role {
field public static final String ROLE_HOME = "android.app.role.HOME";
field public static final String ROLE_NOTES = "android.app.role.NOTES";
field public static final String ROLE_SMS = "android.app.role.SMS";
+ field @FlaggedApi("android.permission.flags.wallet_role_enabled") public static final String ROLE_WALLET = "android.app.role.WALLET";
}
}
diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java
index 3cf1e94ba..fe27d50f3 100644
--- a/framework-s/java/android/app/role/RoleManager.java
+++ b/framework-s/java/android/app/role/RoleManager.java
@@ -146,6 +146,15 @@ public final class RoleManager {
public static final String ROLE_NOTES = "android.app.role.NOTES";
/**
+ * The name of the Wallet role.
+ *
+ * @see android.nfc.cardemulation.CardEmulation
+ */
+ @FlaggedApi(Flags.FLAG_WALLET_ROLE_ENABLED)
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public static final String ROLE_WALLET = "android.app.role.WALLET";
+
+ /**
* The name of the system wellbeing role.
*
* @hide