CardEmulationManager.java revision 31208d3ee36f583fd998c89508a3e93bb550cb29
1da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen/* 2da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * Copyright (C) 2014 The Android Open Source Project 3da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * 4da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License"); 5da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * you may not use this file except in compliance with the License. 6da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * You may obtain a copy of the License at 7da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * 8da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * http://www.apache.org/licenses/LICENSE-2.0 9da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * 10da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * Unless required by applicable law or agreed to in writing, software 11da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS, 12da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * See the License for the specific language governing permissions and 14da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen * limitations under the License. 15da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen */ 16af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenpackage com.android.nfc.cardemulation; 17af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 18af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport java.io.FileDescriptor; 19af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport java.io.PrintWriter; 20af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport java.util.List; 21af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 22af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.content.ComponentName; 23af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.content.Context; 24af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.content.Intent; 25af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.nfc.INfcCardEmulation; 26af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.nfc.cardemulation.AidGroup; 27af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.nfc.cardemulation.ApduServiceInfo; 28af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.nfc.cardemulation.CardEmulation; 29af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.os.Binder; 30af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.os.RemoteException; 31af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.os.UserHandle; 32af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.provider.Settings; 33af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport android.util.Log; 34af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 35af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport com.android.nfc.NfcPermissions; 36da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenenimport com.android.nfc.cardemulation.RegisteredServicesCache; 37af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 38af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen/** 39af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * CardEmulationManager is the central entity 40af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * responsible for delegating to individual components 41af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * implementing card emulation: 42af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * - RegisteredServicesCache keeping track of HCE and SE services on the device 43af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * - RegisteredAidCache keeping track of AIDs registered by those services and manages 44af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * the routing table in the NFCC. 45af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * - HostEmulationManager handles incoming APDUs for the host and forwards to HCE 46af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * services as necessary. 47af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen */ 48da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenenpublic class CardEmulationManager implements RegisteredServicesCache.Callback, 49da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen PreferredServices.Callback { 50af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen static final String TAG = "CardEmulationManager"; 5131208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen static final boolean DBG = true; 52af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 53af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen final RegisteredAidCache mAidCache; 54af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen final RegisteredServicesCache mServiceCache; 55af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen final HostEmulationManager mHostEmulationManager; 56da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen final PreferredServices mPreferredServices; 57af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen final Context mContext; 58af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen final CardEmulationInterface mCardEmulationInterface; 59af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 60af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public CardEmulationManager(Context context) { 61af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mContext = context; 62af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mCardEmulationInterface = new CardEmulationInterface(); 63af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mAidCache = new RegisteredAidCache(context); 64af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mHostEmulationManager = new HostEmulationManager(context, mAidCache); 65af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mServiceCache = new RegisteredServicesCache(context, this); 66da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mPreferredServices = new PreferredServices(context, mServiceCache, this); 67af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 68af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mServiceCache.initialize(); 69af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 70af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 71af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public INfcCardEmulation getNfcCardEmulationInterface() { 72af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mCardEmulationInterface; 73af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 74af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 75af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onHostCardEmulationActivated() { 76af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mHostEmulationManager.onHostEmulationActivated(); 77da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mPreferredServices.onHostEmulationActivated(); 78af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 79af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 80af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onHostCardEmulationData(byte[] data) { 81af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mHostEmulationManager.onHostEmulationData(data); 82af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 83af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 84af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onHostCardEmulationDeactivated() { 85af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mHostEmulationManager.onHostEmulationDeactivated(); 86da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mPreferredServices.onHostEmulationDeactivated(); 87af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 88af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 89af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onOffHostAidSelected() { 90af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mHostEmulationManager.onOffHostAidSelected(); 91af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 92af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 93af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onUserSwitched(int userId) { 94af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mServiceCache.invalidateCache(userId); 95da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mPreferredServices.onUserSwitched(userId); 96af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 97af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 98af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onNfcEnabled() { 99af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mAidCache.onNfcEnabled(); 100af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 101af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 102af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onNfcDisabled() { 103af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mAidCache.onNfcDisabled(); 104af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 105af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 106af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 107af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mServiceCache.dump(fd, pw, args); 108da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mPreferredServices.dump(fd, pw, args); 109af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mAidCache.dump(fd, pw, args); 110da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mHostEmulationManager.dump(fd, pw, args); 111af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 112af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 113af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 114af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public void onServicesUpdated(int userId, List<ApduServiceInfo> services) { 115af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Verify defaults are still sane 116af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen verifyDefaults(userId, services); 117af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Update the AID cache 118af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mAidCache.onServicesUpdated(userId, services); 119ea8bbf3e6a41b4ace768f0b2c74bdcf21e2aee64Martijn Coenen // Update the preferred services list 120ea8bbf3e6a41b4ace768f0b2c74bdcf21e2aee64Martijn Coenen mPreferredServices.onServicesUpdated(); 121af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 122af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 123af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen void verifyDefaults(int userId, List<ApduServiceInfo> services) { 124af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName defaultPaymentService = 125af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen getDefaultServiceForCategory(userId, CardEmulation.CATEGORY_PAYMENT, false); 126af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Current default: " + defaultPaymentService); 127af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (defaultPaymentService != null) { 128af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Validate the default is still installed and handling payment 129af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ApduServiceInfo serviceInfo = mServiceCache.getService(userId, defaultPaymentService); 130af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (serviceInfo == null || !serviceInfo.hasCategory(CardEmulation.CATEGORY_PAYMENT)) { 131af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (serviceInfo == null) { 132af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Log.e(TAG, "Default payment service unexpectedly removed."); 133af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else if (!serviceInfo.hasCategory(CardEmulation.CATEGORY_PAYMENT)) { 134af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Default payment service had payment category removed"); 135af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 136af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen int numPaymentServices = 0; 137af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName lastFoundPaymentService = null; 138af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen for (ApduServiceInfo service : services) { 139af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (service.hasCategory(CardEmulation.CATEGORY_PAYMENT)) { 140af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen numPaymentServices++; 141af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen lastFoundPaymentService = service.getComponent(); 142af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 143af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 144af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Number of payment services is " + 145af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Integer.toString(numPaymentServices)); 146af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (numPaymentServices == 0) { 147af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Default removed, no services left."); 148af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // No payment services left, unset default and don't ask the user 149af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen setDefaultServiceForCategoryChecked(userId, null, CardEmulation.CATEGORY_PAYMENT); 150af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else if (numPaymentServices == 1) { 151af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Only one left, automatically make it the default 152af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Default removed, making remaining service default."); 153af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen setDefaultServiceForCategoryChecked(userId, lastFoundPaymentService, 154af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen CardEmulation.CATEGORY_PAYMENT); 155af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else if (numPaymentServices > 1) { 156af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // More than one left, unset default and ask the user if he wants 157af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // to set a new one 158af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Default removed, asking user to pick."); 159af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen setDefaultServiceForCategoryChecked(userId, null, 160af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen CardEmulation.CATEGORY_PAYMENT); 161af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Intent intent = new Intent(mContext, DefaultRemovedActivity.class); 162af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 163af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mContext.startActivityAsUser(intent, UserHandle.CURRENT); 164af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 165af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else { 166af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Default still exists and handles the category, nothing do 167af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Default payment service still ok."); 168af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 169af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else { 170af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // A payment service may have been removed, leaving only one; 171af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // in that case, automatically set that app as default. 172af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen int numPaymentServices = 0; 173af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName lastFoundPaymentService = null; 174af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen for (ApduServiceInfo service : services) { 175af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (service.hasCategory(CardEmulation.CATEGORY_PAYMENT)) { 176af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen numPaymentServices++; 177af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen lastFoundPaymentService = service.getComponent(); 178af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 179af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 180af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (numPaymentServices > 1) { 181af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // More than one service left, leave default unset 182af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "No default set, more than one service left."); 183af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else if (numPaymentServices == 1) { 184af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Make single found payment service the default 185af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "No default set, making single service default."); 186af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen setDefaultServiceForCategoryChecked(userId, lastFoundPaymentService, 187af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen CardEmulation.CATEGORY_PAYMENT); 188af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else { 189af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // No payment services left, leave default at null 190af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "No default set, last payment service removed."); 191af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 192af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 193af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 194af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 195af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName getDefaultServiceForCategory(int userId, String category, 196af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen boolean validateInstalled) { 197af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) { 198af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Log.e(TAG, "Not allowing defaults for category " + category); 199af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return null; 200af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 201af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Load current payment default from settings 202af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen String name = Settings.Secure.getStringForUser( 203af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, 204af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen userId); 205af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (name != null) { 206af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName service = ComponentName.unflattenFromString(name); 207af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!validateInstalled || service == null) { 208af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return service; 209af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else { 210af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mServiceCache.hasService(userId, service) ? service : null; 211af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 212af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else { 213af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return null; 214af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 215af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 216af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 217af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen boolean setDefaultServiceForCategoryChecked(int userId, ComponentName service, 218af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen String category) { 219af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) { 220af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Log.e(TAG, "Not allowing defaults for category " + category); 221af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 222af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 223af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // TODO Not really nice to be writing to Settings.Secure here... 224af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // ideally we overlay our local changes over whatever is in 225af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Settings.Secure 226af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (service == null || mServiceCache.hasService(userId, service)) { 227af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Settings.Secure.putStringForUser(mContext.getContentResolver(), 228af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, 229af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen service != null ? service.flattenToString() : null, userId); 230af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } else { 231af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen Log.e(TAG, "Could not find default service to make default: " + service); 232af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 233af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return true; 234af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 235af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 236af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen boolean isServiceRegistered(int userId, ComponentName service) { 237af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen boolean serviceFound = mServiceCache.hasService(userId, service); 238af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!serviceFound) { 239af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // If we don't know about this service yet, it may have just been enabled 240af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // using PackageManager.setComponentEnabledSetting(). The PackageManager 241af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // broadcasts are delayed by 10 seconds in that scenario, which causes 242af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // calls to our APIs referencing that service to fail. 243af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen // Hence, update the cache in case we don't know about the service. 244af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (DBG) Log.d(TAG, "Didn't find passed in service, invalidating cache."); 245af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen mServiceCache.invalidateCache(userId); 246af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 247af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mServiceCache.hasService(userId, service); 248af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 249af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 250af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen /** 251af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * This class implements the application-facing APIs 252af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * and are called from binder. All calls must be 253af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * permission-checked. 254af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen * 255af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen */ 256af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen final class CardEmulationInterface extends INfcCardEmulation.Stub { 257af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 258af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public boolean isDefaultServiceForCategory(int userId, ComponentName service, 259af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen String category) { 260af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 261af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 262af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 263af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 264af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 265af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName defaultService = 266af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen getDefaultServiceForCategory(userId, category, true); 267af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return (defaultService != null && defaultService.equals(service)); 268af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 269af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 270af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 271af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public boolean isDefaultServiceForAid(int userId, 272af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName service, String aid) throws RemoteException { 273af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 274af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 275af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 276af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 277af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 278af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mAidCache.isDefaultServiceForAid(userId, service, aid); 279af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 280af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 281af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 282af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public boolean setDefaultServiceForCategory(int userId, 283af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName service, String category) throws RemoteException { 284af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 285af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceAdminPermissions(mContext); 286af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 287af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 288af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 289af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return setDefaultServiceForCategoryChecked(userId, service, category); 290af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 291af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 292af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 293af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public boolean setDefaultForNextTap(int userId, ComponentName service) 294af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen throws RemoteException { 295af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 296af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceAdminPermissions(mContext); 297af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 298af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 299af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 300da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen return mPreferredServices.setDefaultForNextTap(service); 301af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 302af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 303af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 304af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public boolean registerAidGroupForService(int userId, 305af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName service, AidGroup aidGroup) throws RemoteException { 306af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 307af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 308af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 309af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 310af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 311af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mServiceCache.registerAidGroupForService(userId, Binder.getCallingUid(), service, 312af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen aidGroup); 313af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 314af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 315af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 316af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public AidGroup getAidGroupForService(int userId, 317af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName service, String category) throws RemoteException { 318af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 319af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 320af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 321af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return null; 322af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 323af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mServiceCache.getAidGroupForService(userId, Binder.getCallingUid(), service, 324af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen category); 325af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 326af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 327af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 328af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public boolean removeAidGroupForService(int userId, 329af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen ComponentName service, String category) throws RemoteException { 330af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 331af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 332af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen if (!isServiceRegistered(userId, service)) { 333af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return false; 334af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 335af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mServiceCache.removeAidGroupForService(userId, Binder.getCallingUid(), service, 336af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen category); 337af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 338af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen 339af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen @Override 340af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen public List<ApduServiceInfo> getServices(int userId, String category) 341af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen throws RemoteException { 342af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.validateUserId(userId); 343af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen NfcPermissions.enforceAdminPermissions(mContext); 344af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen return mServiceCache.getServicesForCategory(userId, category); 345af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen } 346da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen 347da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen @Override 348da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen public boolean setPreferredService(ComponentName service) 349da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen throws RemoteException { 350da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 351da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen if (!isServiceRegistered(UserHandle.getCallingUserId(), service)) { 35231208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen Log.e(TAG, "setPreferredService: unknown component."); 353da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen return false; 354da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen } 355da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen return mPreferredServices.registerPreferredForegroundService(service, 356da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen Binder.getCallingUid()); 357da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen } 358da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen 359da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen @Override 360da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen public boolean unsetPreferredService() throws RemoteException { 361da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen NfcPermissions.enforceUserPermissions(mContext); 362da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen return mPreferredServices.unregisteredPreferredForegroundService( 363da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen Binder.getCallingUid()); 364da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen 365da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen } 36631208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen 36731208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen @Override 36831208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen public boolean supportsAidPrefixRegistration() throws RemoteException { 36931208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen return mAidCache.supportsAidPrefixRegistration(); 37031208d3ee36f583fd998c89508a3e93bb550cb29Martijn Coenen } 371da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen } 372da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen 373da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen @Override 374da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen public void onPreferredPaymentServiceChanged(ComponentName service) { 375da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mAidCache.onPreferredPaymentServiceChanged(service); 376da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mHostEmulationManager.onPreferredPaymentServiceChanged(service); 377da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen } 378da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen 379da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen @Override 380da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen public void onPreferredForegroundServiceChanged(ComponentName service) { 381da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mAidCache.onPreferredForegroundServiceChanged(service); 382da772582c17e3f5ffe36e4cab3e1ede3cba32060Martijn Coenen mHostEmulationManager.onPreferredForegroundServiceChanged(service); 383af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen }; 384e6f2dc6731bccc8ea01c8d9d03dd7e90f2c00312Martijn Coenen} 385