Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.settings.nfc; |
| 18 | |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 19 | import android.app.ActivityManager; |
Martijn Coenen | 6d5cac5 | 2015-06-05 11:36:50 +0200 | [diff] [blame] | 20 | import android.content.ComponentName; |
| 21 | import android.content.Context; |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 22 | import android.content.pm.PackageManager; |
Jack Yu | 9de30f0 | 2022-01-04 17:40:55 +0800 | [diff] [blame] | 23 | import android.graphics.drawable.Drawable; |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 24 | import android.nfc.NfcAdapter; |
| 25 | import android.nfc.cardemulation.ApduServiceInfo; |
Martijn Coenen | a73aa32 | 2013-08-30 12:57:42 -0700 | [diff] [blame] | 26 | import android.nfc.cardemulation.CardEmulation; |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 27 | import android.os.Handler; |
chiujason | ff244c0 | 2018-04-12 15:52:00 +0800 | [diff] [blame] | 28 | import android.os.Looper; |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 29 | import android.os.Message; |
chiujason | ff244c0 | 2018-04-12 15:52:00 +0800 | [diff] [blame] | 30 | import android.os.UserHandle; |
Jack Yu | d2ca403 | 2021-07-26 22:13:50 +0800 | [diff] [blame] | 31 | import android.os.UserManager; |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 32 | import android.provider.Settings; |
Martijn Coenen | 00dbb74 | 2014-04-25 16:58:59 -0700 | [diff] [blame] | 33 | import android.provider.Settings.SettingNotFoundException; |
Jason Monk | 39b4674 | 2015-09-10 15:52:51 -0400 | [diff] [blame] | 34 | |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 35 | import com.android.internal.content.PackageMonitor; |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 36 | |
| 37 | import java.util.ArrayList; |
| 38 | import java.util.List; |
| 39 | |
| 40 | public class PaymentBackend { |
| 41 | public static final String TAG = "Settings.PaymentBackend"; |
| 42 | |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 43 | public interface Callback { |
| 44 | void onPaymentAppsChanged(); |
| 45 | } |
| 46 | |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 47 | public static class PaymentAppInfo { |
Fan Zhang | 2ea6700 | 2017-07-11 16:26:58 -0700 | [diff] [blame] | 48 | public CharSequence label; |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 49 | CharSequence description; |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 50 | boolean isDefault; |
| 51 | public ComponentName componentName; |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 52 | public ComponentName settingsComponent; |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 53 | public UserHandle userHandle; |
Jack Yu | 9de30f0 | 2022-01-04 17:40:55 +0800 | [diff] [blame] | 54 | public Drawable icon; |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | /** |
| 58 | * ComponentName of the payment application and the userId that it belongs to. |
| 59 | */ |
| 60 | public static class PaymentInfo { |
| 61 | public ComponentName componentName; |
| 62 | public int userId; |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | private final Context mContext; |
| 66 | private final NfcAdapter mAdapter; |
Martijn Coenen | a73aa32 | 2013-08-30 12:57:42 -0700 | [diff] [blame] | 67 | private final CardEmulation mCardEmuManager; |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 68 | private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor(); |
| 69 | // Fields below only modified on UI thread |
| 70 | private ArrayList<PaymentAppInfo> mAppInfos; |
| 71 | private PaymentAppInfo mDefaultAppInfo; |
chiujason | ff244c0 | 2018-04-12 15:52:00 +0800 | [diff] [blame] | 72 | private ArrayList<Callback> mCallbacks = new ArrayList<>(); |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 73 | |
| 74 | public PaymentBackend(Context context) { |
| 75 | mContext = context; |
| 76 | |
| 77 | mAdapter = NfcAdapter.getDefaultAdapter(context); |
Martijn Coenen | a73aa32 | 2013-08-30 12:57:42 -0700 | [diff] [blame] | 78 | mCardEmuManager = CardEmulation.getInstance(mAdapter); |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 79 | refresh(); |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 80 | } |
| 81 | |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 82 | public void onPause() { |
| 83 | mSettingsPackageMonitor.unregister(); |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | public void onResume() { |
| 87 | mSettingsPackageMonitor.register(mContext, mContext.getMainLooper(), false); |
Cai, Min1 | 0b97d35 | 2017-10-11 17:31:22 +0900 | [diff] [blame] | 88 | refresh(); |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | public void refresh() { |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 92 | PackageManager pm = mContext.getPackageManager(); |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 93 | ArrayList<PaymentAppInfo> appInfosAllProfiles = new ArrayList<PaymentAppInfo>(); |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 94 | |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 95 | UserManager um = mContext.createContextAsUser( |
| 96 | UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) |
| 97 | .getSystemService(UserManager.class); |
| 98 | List<UserHandle> userHandles = um.getEnabledProfiles(); |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 99 | |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 100 | PaymentInfo defaultAppName = getDefaultPaymentApp(); |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 101 | PaymentAppInfo foundDefaultApp = null; |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 102 | for (UserHandle uh : userHandles) { |
| 103 | List<ApduServiceInfo> serviceInfosByProfile = |
| 104 | mCardEmuManager.getServices(CardEmulation.CATEGORY_PAYMENT, uh.getIdentifier()); |
| 105 | if (serviceInfosByProfile == null) continue; |
| 106 | |
| 107 | ArrayList<PaymentAppInfo> appInfos = new ArrayList<PaymentAppInfo>(); |
| 108 | |
| 109 | for (ApduServiceInfo service : serviceInfosByProfile) { |
| 110 | PaymentAppInfo appInfo = new PaymentAppInfo(); |
| 111 | appInfo.userHandle = uh; |
| 112 | appInfo.label = service.loadLabel(pm); |
| 113 | if (appInfo.label == null) { |
| 114 | appInfo.label = service.loadAppLabel(pm); |
| 115 | } |
| 116 | if (defaultAppName == null) { |
| 117 | appInfo.isDefault = false; |
| 118 | } else { |
| 119 | appInfo.isDefault = |
| 120 | service.getComponent().equals(defaultAppName.componentName) |
| 121 | && defaultAppName.userId == uh.getIdentifier(); |
| 122 | } |
| 123 | if (appInfo.isDefault) { |
| 124 | foundDefaultApp = appInfo; |
| 125 | } |
| 126 | appInfo.componentName = service.getComponent(); |
| 127 | String settingsActivity = service.getSettingsActivityName(); |
| 128 | if (settingsActivity != null) { |
| 129 | appInfo.settingsComponent = new ComponentName( |
| 130 | appInfo.componentName.getPackageName(), |
| 131 | settingsActivity); |
| 132 | } else { |
| 133 | appInfo.settingsComponent = null; |
| 134 | } |
| 135 | appInfo.description = service.getDescription(); |
Jack Yu | 1e9a9cd | 2022-02-09 21:49:28 +0800 | [diff] [blame] | 136 | Drawable icon = (service.loadBanner(pm) != null) |
| 137 | ? service.loadBanner(pm) : service.loadIcon(pm); |
| 138 | appInfo.icon = pm.getUserBadgedIcon(icon, appInfo.userHandle); |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 139 | |
| 140 | appInfos.add(appInfo); |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 141 | } |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 142 | appInfosAllProfiles.addAll(appInfos); |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 143 | } |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 144 | mAppInfos = appInfosAllProfiles; |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 145 | mDefaultAppInfo = foundDefaultApp; |
| 146 | makeCallbacks(); |
| 147 | } |
| 148 | |
| 149 | public void registerCallback(Callback callback) { |
| 150 | mCallbacks.add(callback); |
| 151 | } |
| 152 | |
| 153 | public void unregisterCallback(Callback callback) { |
| 154 | mCallbacks.remove(callback); |
| 155 | } |
| 156 | |
| 157 | public List<PaymentAppInfo> getPaymentAppInfos() { |
| 158 | return mAppInfos; |
| 159 | } |
| 160 | |
| 161 | public PaymentAppInfo getDefaultApp() { |
| 162 | return mDefaultAppInfo; |
| 163 | } |
| 164 | |
| 165 | void makeCallbacks() { |
| 166 | for (Callback callback : mCallbacks) { |
| 167 | callback.onPaymentAppsChanged(); |
| 168 | } |
| 169 | } |
| 170 | |
Martijn Coenen | 00dbb74 | 2014-04-25 16:58:59 -0700 | [diff] [blame] | 171 | boolean isForegroundMode() { |
| 172 | try { |
Jack Yu | d2ca403 | 2021-07-26 22:13:50 +0800 | [diff] [blame] | 173 | return Settings.Secure.getIntForUser(mContext.getContentResolver(), |
| 174 | Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0; |
Martijn Coenen | 00dbb74 | 2014-04-25 16:58:59 -0700 | [diff] [blame] | 175 | } catch (SettingNotFoundException e) { |
| 176 | return false; |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | void setForegroundMode(boolean foreground) { |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 181 | UserManager um = mContext.createContextAsUser( |
| 182 | UserHandle.of(UserHandle.myUserId()), /*flags=*/0) |
| 183 | .getSystemService(UserManager.class); |
| 184 | List<UserHandle> userHandles = um.getEnabledProfiles(); |
| 185 | for (UserHandle uh : userHandles) { |
| 186 | Settings.Secure.putIntForUser(mContext.getContentResolver(), |
| 187 | Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0, uh.getIdentifier()); |
| 188 | } |
Martijn Coenen | 00dbb74 | 2014-04-25 16:58:59 -0700 | [diff] [blame] | 189 | } |
| 190 | |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 191 | PaymentInfo getDefaultPaymentApp() { |
| 192 | UserManager um = mContext.createContextAsUser( |
| 193 | UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) |
| 194 | .getSystemService(UserManager.class); |
| 195 | List<UserHandle> userHandles = um.getEnabledProfiles(); |
| 196 | for (UserHandle uh : userHandles) { |
| 197 | ComponentName defaultApp = getDefaultPaymentApp(uh.getIdentifier()); |
| 198 | if (defaultApp != null) { |
| 199 | PaymentInfo appInfo = new PaymentInfo(); |
| 200 | appInfo.userId = uh.getIdentifier(); |
| 201 | appInfo.componentName = defaultApp; |
| 202 | return appInfo; |
| 203 | } |
| 204 | } |
| 205 | return null; |
| 206 | } |
| 207 | |
| 208 | ComponentName getDefaultPaymentApp(int userId) { |
Jack Yu | d2ca403 | 2021-07-26 22:13:50 +0800 | [diff] [blame] | 209 | String componentString = Settings.Secure.getStringForUser(mContext.getContentResolver(), |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 210 | Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, userId); |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 211 | if (componentString != null) { |
| 212 | return ComponentName.unflattenFromString(componentString); |
| 213 | } else { |
| 214 | return null; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | public void setDefaultPaymentApp(ComponentName app) { |
Jack Yu | 2a2e027 | 2021-10-13 19:56:09 +0800 | [diff] [blame] | 219 | setDefaultPaymentApp(app, UserHandle.myUserId()); |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Set Nfc default payment application |
| 224 | */ |
| 225 | public void setDefaultPaymentApp(ComponentName app, int userId) { |
| 226 | UserManager um = mContext.createContextAsUser( |
| 227 | UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) |
| 228 | .getSystemService(UserManager.class); |
| 229 | List<UserHandle> userHandles = um.getEnabledProfiles(); |
| 230 | |
| 231 | for (UserHandle uh : userHandles) { |
| 232 | if (uh.getIdentifier() == userId) { |
| 233 | Settings.Secure.putStringForUser(mContext.getContentResolver(), |
| 234 | Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, |
| 235 | app != null ? app.flattenToString() : null, uh.getIdentifier()); |
| 236 | } else { |
| 237 | Settings.Secure.putStringForUser(mContext.getContentResolver(), |
| 238 | Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, |
| 239 | null, uh.getIdentifier()); |
| 240 | } |
| 241 | } |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 242 | refresh(); |
| 243 | } |
| 244 | |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 245 | private class SettingsPackageMonitor extends PackageMonitor { |
chiujason | ff244c0 | 2018-04-12 15:52:00 +0800 | [diff] [blame] | 246 | private Handler mHandler; |
| 247 | |
| 248 | @Override |
| 249 | public void register(Context context, Looper thread, UserHandle user, |
| 250 | boolean externalStorage) { |
| 251 | if (mHandler == null) { |
| 252 | mHandler = new Handler(thread) { |
| 253 | @Override |
| 254 | public void dispatchMessage(Message msg) { |
| 255 | refresh(); |
| 256 | } |
| 257 | }; |
| 258 | } |
| 259 | super.register(context, thread, user, externalStorage); |
| 260 | } |
| 261 | |
Martijn Coenen | fe58b53 | 2015-04-21 13:47:55 +0200 | [diff] [blame] | 262 | @Override |
| 263 | public void onPackageAdded(String packageName, int uid) { |
| 264 | mHandler.obtainMessage().sendToTarget(); |
| 265 | } |
| 266 | |
| 267 | @Override |
| 268 | public void onPackageAppeared(String packageName, int reason) { |
| 269 | mHandler.obtainMessage().sendToTarget(); |
| 270 | } |
| 271 | |
| 272 | @Override |
| 273 | public void onPackageDisappeared(String packageName, int reason) { |
| 274 | mHandler.obtainMessage().sendToTarget(); |
| 275 | } |
| 276 | |
| 277 | @Override |
| 278 | public void onPackageRemoved(String packageName, int uid) { |
| 279 | mHandler.obtainMessage().sendToTarget(); |
| 280 | } |
Martijn Coenen | 26515da | 2013-08-01 18:13:33 -0700 | [diff] [blame] | 281 | } |
George Chang | 8adb77f | 2019-02-15 18:48:43 +0800 | [diff] [blame] | 282 | } |