/* * Copyright (C) 2013 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.settings.nfc; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.nfc.NfcAdapter; import android.nfc.cardemulation.ApduServiceInfo; import android.nfc.cardemulation.CardEmulation; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import com.android.internal.content.PackageMonitor; import java.util.ArrayList; import java.util.List; public class PaymentBackend { public static final String TAG = "Settings.PaymentBackend"; public interface Callback { void onPaymentAppsChanged(); } public static class PaymentAppInfo { public CharSequence label; CharSequence description; boolean isDefault; public ComponentName componentName; public ComponentName settingsComponent; public UserHandle userHandle; public Drawable icon; } /** * ComponentName of the payment application and the userId that it belongs to. */ public static class PaymentInfo { public ComponentName componentName; public int userId; } private final Context mContext; private final NfcAdapter mAdapter; private final CardEmulation mCardEmuManager; private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor(); // Fields below only modified on UI thread private ArrayList mAppInfos; private PaymentAppInfo mDefaultAppInfo; private ArrayList mCallbacks = new ArrayList<>(); public PaymentBackend(Context context) { mContext = context; mAdapter = NfcAdapter.getDefaultAdapter(context); mCardEmuManager = CardEmulation.getInstance(mAdapter); refresh(); } public void onPause() { mSettingsPackageMonitor.unregister(); } public void onResume() { mSettingsPackageMonitor.register(mContext, mContext.getMainLooper(), false); refresh(); } public void refresh() { PackageManager pm = mContext.getPackageManager(); ArrayList appInfosAllProfiles = new ArrayList(); UserManager um = mContext.createContextAsUser( UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) .getSystemService(UserManager.class); List userHandles = um.getEnabledProfiles(); PaymentInfo defaultAppName = getDefaultPaymentApp(); PaymentAppInfo foundDefaultApp = null; for (UserHandle uh : userHandles) { List serviceInfosByProfile = mCardEmuManager.getServices(CardEmulation.CATEGORY_PAYMENT, uh.getIdentifier()); if (serviceInfosByProfile == null) continue; ArrayList appInfos = new ArrayList(); for (ApduServiceInfo service : serviceInfosByProfile) { PaymentAppInfo appInfo = new PaymentAppInfo(); appInfo.userHandle = uh; appInfo.label = service.loadLabel(pm); if (appInfo.label == null) { appInfo.label = service.loadAppLabel(pm); } if (defaultAppName == null) { appInfo.isDefault = false; } else { appInfo.isDefault = service.getComponent().equals(defaultAppName.componentName) && defaultAppName.userId == uh.getIdentifier(); } if (appInfo.isDefault) { foundDefaultApp = appInfo; } appInfo.componentName = service.getComponent(); String settingsActivity = service.getSettingsActivityName(); if (settingsActivity != null) { appInfo.settingsComponent = new ComponentName( appInfo.componentName.getPackageName(), settingsActivity); } else { appInfo.settingsComponent = null; } appInfo.description = service.getDescription(); Drawable icon = (service.loadBanner(pm) != null) ? service.loadBanner(pm) : service.loadIcon(pm); appInfo.icon = pm.getUserBadgedIcon(icon, appInfo.userHandle); appInfos.add(appInfo); } appInfosAllProfiles.addAll(appInfos); } mAppInfos = appInfosAllProfiles; mDefaultAppInfo = foundDefaultApp; makeCallbacks(); } public void registerCallback(Callback callback) { mCallbacks.add(callback); } public void unregisterCallback(Callback callback) { mCallbacks.remove(callback); } public List getPaymentAppInfos() { return mAppInfos; } public PaymentAppInfo getDefaultApp() { return mDefaultAppInfo; } void makeCallbacks() { for (Callback callback : mCallbacks) { callback.onPaymentAppsChanged(); } } boolean isForegroundMode() { try { return Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0; } catch (SettingNotFoundException e) { return false; } } void setForegroundMode(boolean foreground) { UserManager um = mContext.createContextAsUser( UserHandle.of(UserHandle.myUserId()), /*flags=*/0) .getSystemService(UserManager.class); List userHandles = um.getEnabledProfiles(); for (UserHandle uh : userHandles) { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0, uh.getIdentifier()); } } PaymentInfo getDefaultPaymentApp() { UserManager um = mContext.createContextAsUser( UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) .getSystemService(UserManager.class); List userHandles = um.getEnabledProfiles(); for (UserHandle uh : userHandles) { ComponentName defaultApp = getDefaultPaymentApp(uh.getIdentifier()); if (defaultApp != null) { PaymentInfo appInfo = new PaymentInfo(); appInfo.userId = uh.getIdentifier(); appInfo.componentName = defaultApp; return appInfo; } } return null; } ComponentName getDefaultPaymentApp(int userId) { String componentString = Settings.Secure.getStringForUser(mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, userId); if (componentString != null) { return ComponentName.unflattenFromString(componentString); } else { return null; } } public void setDefaultPaymentApp(ComponentName app) { setDefaultPaymentApp(app, UserHandle.myUserId()); } /** * Set Nfc default payment application */ public void setDefaultPaymentApp(ComponentName app, int userId) { UserManager um = mContext.createContextAsUser( UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) .getSystemService(UserManager.class); List userHandles = um.getEnabledProfiles(); for (UserHandle uh : userHandles) { if (uh.getIdentifier() == userId) { Settings.Secure.putStringForUser(mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, app != null ? app.flattenToString() : null, uh.getIdentifier()); } else { Settings.Secure.putStringForUser(mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, null, uh.getIdentifier()); } } refresh(); } private class SettingsPackageMonitor extends PackageMonitor { private Handler mHandler; @Override public void register(Context context, Looper thread, UserHandle user, boolean externalStorage) { if (mHandler == null) { mHandler = new Handler(thread) { @Override public void dispatchMessage(Message msg) { refresh(); } }; } super.register(context, thread, user, externalStorage); } @Override public void onPackageAdded(String packageName, int uid) { mHandler.obtainMessage().sendToTarget(); } @Override public void onPackageAppeared(String packageName, int reason) { mHandler.obtainMessage().sendToTarget(); } @Override public void onPackageDisappeared(String packageName, int reason) { mHandler.obtainMessage().sendToTarget(); } @Override public void onPackageRemoved(String packageName, int uid) { mHandler.obtainMessage().sendToTarget(); } } }