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 19 import android.app.ActivityManager; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.pm.PackageManager; 23 import android.graphics.drawable.Drawable; 24 import android.nfc.NfcAdapter; 25 import android.nfc.cardemulation.ApduServiceInfo; 26 import android.nfc.cardemulation.CardEmulation; 27 import android.os.Handler; 28 import android.os.Looper; 29 import android.os.Message; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.provider.Settings; 33 import android.provider.Settings.SettingNotFoundException; 34 35 import com.android.internal.content.PackageMonitor; 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 43 public interface Callback { onPaymentAppsChanged()44 void onPaymentAppsChanged(); 45 } 46 47 public static class PaymentAppInfo { 48 public CharSequence label; 49 CharSequence description; 50 boolean isDefault; 51 public ComponentName componentName; 52 public ComponentName settingsComponent; 53 public UserHandle userHandle; 54 public Drawable icon; 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; 63 } 64 65 private final Context mContext; 66 private final NfcAdapter mAdapter; 67 private final CardEmulation mCardEmuManager; 68 private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor(); 69 // Fields below only modified on UI thread 70 private ArrayList<PaymentAppInfo> mAppInfos; 71 private PaymentAppInfo mDefaultAppInfo; 72 private ArrayList<Callback> mCallbacks = new ArrayList<>(); 73 PaymentBackend(Context context)74 public PaymentBackend(Context context) { 75 mContext = context; 76 77 mAdapter = NfcAdapter.getDefaultAdapter(context); 78 mCardEmuManager = CardEmulation.getInstance(mAdapter); 79 refresh(); 80 } 81 onPause()82 public void onPause() { 83 mSettingsPackageMonitor.unregister(); 84 } 85 onResume()86 public void onResume() { 87 mSettingsPackageMonitor.register(mContext, mContext.getMainLooper(), false); 88 refresh(); 89 } 90 refresh()91 public void refresh() { 92 PackageManager pm = mContext.getPackageManager(); 93 ArrayList<PaymentAppInfo> appInfosAllProfiles = new ArrayList<PaymentAppInfo>(); 94 95 UserManager um = mContext.createContextAsUser( 96 UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) 97 .getSystemService(UserManager.class); 98 List<UserHandle> userHandles = um.getEnabledProfiles(); 99 100 PaymentInfo defaultAppName = getDefaultPaymentApp(); 101 PaymentAppInfo foundDefaultApp = null; 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(); 136 Drawable icon = (service.loadBanner(pm) != null) 137 ? service.loadBanner(pm) : service.loadIcon(pm); 138 appInfo.icon = pm.getUserBadgedIcon(icon, appInfo.userHandle); 139 140 appInfos.add(appInfo); 141 } 142 appInfosAllProfiles.addAll(appInfos); 143 } 144 mAppInfos = appInfosAllProfiles; 145 mDefaultAppInfo = foundDefaultApp; 146 makeCallbacks(); 147 } 148 registerCallback(Callback callback)149 public void registerCallback(Callback callback) { 150 mCallbacks.add(callback); 151 } 152 unregisterCallback(Callback callback)153 public void unregisterCallback(Callback callback) { 154 mCallbacks.remove(callback); 155 } 156 getPaymentAppInfos()157 public List<PaymentAppInfo> getPaymentAppInfos() { 158 return mAppInfos; 159 } 160 getDefaultApp()161 public PaymentAppInfo getDefaultApp() { 162 return mDefaultAppInfo; 163 } 164 makeCallbacks()165 void makeCallbacks() { 166 for (Callback callback : mCallbacks) { 167 callback.onPaymentAppsChanged(); 168 } 169 } 170 isForegroundMode()171 boolean isForegroundMode() { 172 try { 173 return Settings.Secure.getIntForUser(mContext.getContentResolver(), 174 Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0; 175 } catch (SettingNotFoundException e) { 176 return false; 177 } 178 } 179 setForegroundMode(boolean foreground)180 void setForegroundMode(boolean foreground) { 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 } 189 } 190 getDefaultPaymentApp()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 getDefaultPaymentApp(int userId)208 ComponentName getDefaultPaymentApp(int userId) { 209 String componentString = Settings.Secure.getStringForUser(mContext.getContentResolver(), 210 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, userId); 211 if (componentString != null) { 212 return ComponentName.unflattenFromString(componentString); 213 } else { 214 return null; 215 } 216 } 217 setDefaultPaymentApp(ComponentName app)218 public void setDefaultPaymentApp(ComponentName app) { 219 setDefaultPaymentApp(app, UserHandle.myUserId()); 220 } 221 222 /** 223 * Set Nfc default payment application 224 */ setDefaultPaymentApp(ComponentName app, int userId)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 } 242 refresh(); 243 } 244 245 private class SettingsPackageMonitor extends PackageMonitor { 246 private Handler mHandler; 247 248 @Override register(Context context, Looper thread, UserHandle user, boolean externalStorage)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 262 @Override onPackageAdded(String packageName, int uid)263 public void onPackageAdded(String packageName, int uid) { 264 mHandler.obtainMessage().sendToTarget(); 265 } 266 267 @Override onPackageAppeared(String packageName, int reason)268 public void onPackageAppeared(String packageName, int reason) { 269 mHandler.obtainMessage().sendToTarget(); 270 } 271 272 @Override onPackageDisappeared(String packageName, int reason)273 public void onPackageDisappeared(String packageName, int reason) { 274 mHandler.obtainMessage().sendToTarget(); 275 } 276 277 @Override onPackageRemoved(String packageName, int uid)278 public void onPackageRemoved(String packageName, int uid) { 279 mHandler.obtainMessage().sendToTarget(); 280 } 281 } 282 } 283