152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen/* 252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Copyright (C) 2013 The Android Open Source Project 352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License"); 552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * you may not use this file except in compliance with the License. 652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * You may obtain a copy of the License at 752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * http://www.apache.org/licenses/LICENSE-2.0 952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 1052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Unless required by applicable law or agreed to in writing, software 1152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS, 1252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * See the License for the specific language governing permissions and 1452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * limitations under the License. 1552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 1652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 1752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenpackage android.nfc.cardemulation; 1852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 1952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.annotation.SdkConstant; 2052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.annotation.SdkConstant.SdkConstantType; 212f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenenimport android.app.Activity; 2252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.app.ActivityThread; 2352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.ComponentName; 2452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.Context; 2552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.IPackageManager; 2652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.PackageManager; 2752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.INfcCardEmulation; 2852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.NfcAdapter; 2952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.RemoteException; 3052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.UserHandle; 3152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.provider.Settings; 322f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenenimport android.provider.Settings.SettingNotFoundException; 3352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.util.Log; 3452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 3552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.HashMap; 3652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.List; 3752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 3835bf6288527b177a04100585321a1266f020004aMartijn Coenen/** 3935bf6288527b177a04100585321a1266f020004aMartijn Coenen * This class can be used to query the state of 4035bf6288527b177a04100585321a1266f020004aMartijn Coenen * NFC card emulation services. 4135bf6288527b177a04100585321a1266f020004aMartijn Coenen * 4235bf6288527b177a04100585321a1266f020004aMartijn Coenen * For a general introduction into NFC card emulation, 43f64c80a6cd46ce40018f66ae6f156c5f56bb68d3Robert Schaub * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html"> 4435bf6288527b177a04100585321a1266f020004aMartijn Coenen * NFC card emulation developer guide</a>.</p> 4535bf6288527b177a04100585321a1266f020004aMartijn Coenen * 4635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p class="note">Use of this class requires the 4735bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present 4835bf6288527b177a04100585321a1266f020004aMartijn Coenen * on the device. 4935bf6288527b177a04100585321a1266f020004aMartijn Coenen */ 5052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenpublic final class CardEmulation { 5152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static final String TAG = "CardEmulation"; 5252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 5352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 5452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Activity action: ask the user to change the default 5552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * card emulation service for a certain category. This will 5652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * show a dialog that asks the user whether he wants to 5752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * replace the current default service with the service 5852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * identified with the ComponentName specified in 5952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * {@link #EXTRA_SERVICE_COMPONENT}, for the category 6052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * specified in {@link #EXTRA_CATEGORY} 6152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 6252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 6352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String ACTION_CHANGE_DEFAULT = 6452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; 6552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 6652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 6735bf6288527b177a04100585321a1266f020004aMartijn Coenen * The category extra for {@link #ACTION_CHANGE_DEFAULT}. 6852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 6952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @see #ACTION_CHANGE_DEFAULT 7052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 7152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String EXTRA_CATEGORY = "category"; 7252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 7352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 7435bf6288527b177a04100585321a1266f020004aMartijn Coenen * The service {@link ComponentName} object passed in as an 7535bf6288527b177a04100585321a1266f020004aMartijn Coenen * extra for {@link #ACTION_CHANGE_DEFAULT}. 7652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 7752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @see #ACTION_CHANGE_DEFAULT 7852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 7952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String EXTRA_SERVICE_COMPONENT = "component"; 8052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 8152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 8235bf6288527b177a04100585321a1266f020004aMartijn Coenen * Category used for NFC payment services. 8352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 8452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String CATEGORY_PAYMENT = "payment"; 8552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 8652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 8735bf6288527b177a04100585321a1266f020004aMartijn Coenen * Category that can be used for all other card emulation 8835bf6288527b177a04100585321a1266f020004aMartijn Coenen * services. 8952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 9052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String CATEGORY_OTHER = "other"; 9152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 9252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 9352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Return value for {@link #getSelectionModeForCategory(String)}. 9452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 9552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>In this mode, the user has set a default service for this 9635bf6288527b177a04100585321a1266f020004aMartijn Coenen * category. 9735bf6288527b177a04100585321a1266f020004aMartijn Coenen * 9835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>When using ISO-DEP card emulation with {@link HostApduService} 9935bf6288527b177a04100585321a1266f020004aMartijn Coenen * or {@link OffHostApduService}, if a remote NFC device selects 10035bf6288527b177a04100585321a1266f020004aMartijn Coenen * any of the Application IDs (AIDs) 10152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * that the default service has registered in this category, 10252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * that service will automatically be bound to to handle 10352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the transaction. 10452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 10552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final int SELECTION_MODE_PREFER_DEFAULT = 0; 10652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 10752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 10852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Return value for {@link #getSelectionModeForCategory(String)}. 10952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 11035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService} 11135bf6288527b177a04100585321a1266f020004aMartijn Coenen * or {@link OffHostApduService}, whenever an Application ID (AID) of this category 11235bf6288527b177a04100585321a1266f020004aMartijn Coenen * is selected, the user is asked which service he wants to use to handle 11352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the transaction, even if there is only one matching service. 11452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 11552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final int SELECTION_MODE_ALWAYS_ASK = 1; 11652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 11752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 11852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Return value for {@link #getSelectionModeForCategory(String)}. 11952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 12035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService} 12135bf6288527b177a04100585321a1266f020004aMartijn Coenen * or {@link OffHostApduService}, the user will only be asked to select a service 12235bf6288527b177a04100585321a1266f020004aMartijn Coenen * if the Application ID (AID) selected by the reader has been registered by multiple 12335bf6288527b177a04100585321a1266f020004aMartijn Coenen * services. If there is only one service that has registered for the AID, 12435bf6288527b177a04100585321a1266f020004aMartijn Coenen * that service will be invoked directly. 12552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 12652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; 12752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 12852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static boolean sIsInitialized = false; 12935bf6288527b177a04100585321a1266f020004aMartijn Coenen static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>(); 13052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static INfcCardEmulation sService; 13152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 13252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen final Context mContext; 13352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 13452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen private CardEmulation(Context context, INfcCardEmulation service) { 13552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen mContext = context.getApplicationContext(); 13652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sService = service; 13752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 13852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 13935bf6288527b177a04100585321a1266f020004aMartijn Coenen /** 14035bf6288527b177a04100585321a1266f020004aMartijn Coenen * Helper to get an instance of this class. 14135bf6288527b177a04100585321a1266f020004aMartijn Coenen * 14235bf6288527b177a04100585321a1266f020004aMartijn Coenen * @param adapter A reference to an NfcAdapter object. 14335bf6288527b177a04100585321a1266f020004aMartijn Coenen * @return 14435bf6288527b177a04100585321a1266f020004aMartijn Coenen */ 14552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static synchronized CardEmulation getInstance(NfcAdapter adapter) { 14652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (adapter == null) throw new NullPointerException("NfcAdapter is null"); 14752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Context context = adapter.getContext(); 14852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (context == null) { 14952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "NfcAdapter context is null."); 15052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 15152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 15252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (!sIsInitialized) { 15352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen IPackageManager pm = ActivityThread.getPackageManager(); 15452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (pm == null) { 15552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Cannot get PackageManager"); 15652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 15752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 15852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 159115d2c189a46f535778d9dd0923f703ff2f888feJeff Sharkey if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) { 16052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "This device does not support card emulation"); 16152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 16252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 16352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 16452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "PackageManager query failed."); 16552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 16652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 16752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sIsInitialized = true; 16852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 16952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen CardEmulation manager = sCardEmus.get(context); 17052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (manager == null) { 17152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Get card emu service 17252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen INfcCardEmulation service = adapter.getCardEmulationService(); 173aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen if (service == null) { 174aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "This device does not implement the INfcCardEmulation interface."); 175aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen throw new UnsupportedOperationException(); 176aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 17752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen manager = new CardEmulation(context, service); 17852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sCardEmus.put(context, manager); 17952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 18052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return manager; 18152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 18252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 18352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 18452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Allows an application to query whether a service is currently 18552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the default service to handle a card emulation category. 18652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 18752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>Note that if {@link #getSelectionModeForCategory(String)} 18835bf6288527b177a04100585321a1266f020004aMartijn Coenen * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT}, 18935bf6288527b177a04100585321a1266f020004aMartijn Coenen * this method will always return false. That is because in these 19035bf6288527b177a04100585321a1266f020004aMartijn Coenen * selection modes a default can't be set at the category level. For categories where 19135bf6288527b177a04100585321a1266f020004aMartijn Coenen * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or 19235bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use 19335bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service 19435bf6288527b177a04100585321a1266f020004aMartijn Coenen * is the default for a specific AID. 19552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 19652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param service The ComponentName of the service 19752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param category The category 19852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @return whether service is currently the default service for the category. 19935bf6288527b177a04100585321a1266f020004aMartijn Coenen * 20035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 20152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 20252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean isDefaultServiceForCategory(ComponentName service, String category) { 20352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 20452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category); 20552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 20652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 20752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 20852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 20952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 21052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 21152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 21252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 21352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, 21452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen category); 21552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 21652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 21752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 21852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 21952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 22052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 22152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 22252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 22352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 22452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Allows an application to query whether a service is currently 22552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the default handler for a specified ISO7816-4 Application ID. 22652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 22752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param service The ComponentName of the service 22852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param aid The ISO7816-4 Application ID 22935bf6288527b177a04100585321a1266f020004aMartijn Coenen * @return whether the service is the default handler for the specified AID 23035bf6288527b177a04100585321a1266f020004aMartijn Coenen * 23135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 23252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 23352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean isDefaultServiceForAid(ComponentName service, String aid) { 23452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 23552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid); 23652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 23752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 23852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 23952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 24052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 24152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 24252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 24352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 24452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid); 24552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 24652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 24752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 24852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 24952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 25052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 25152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 25252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 2532f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * Returns whether the user has allowed AIDs registered in the 2542f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * specified category to be handled by a service that is preferred 2552f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * by the foreground application, instead of by a pre-configured default. 2562f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 2572f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * Foreground applications can set such preferences using the 2582f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * {@link #setPreferredService(Activity, ComponentName)} method. 2592f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 2602f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @param category The category, e.g. {@link #CATEGORY_PAYMENT} 2612f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @return whether AIDs in the category can be handled by a service 2622f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * specified by the foreground app. 2632f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen */ 2642f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen public boolean categoryAllowsForegroundPreference(String category) { 2652f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (CATEGORY_PAYMENT.equals(category)) { 2662f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen boolean preferForeground = false; 2672f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen try { 2682f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen preferForeground = Settings.Secure.getInt(mContext.getContentResolver(), 2692f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0; 2702f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } catch (SettingNotFoundException e) { 2712f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 2722f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return preferForeground; 2732f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } else { 2742f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen // Allowed for all other categories 2752f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return true; 2762f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 2772f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 2782f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen 2792f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen /** 28035bf6288527b177a04100585321a1266f020004aMartijn Coenen * Returns the service selection mode for the passed in category. 28152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Valid return values are: 28252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default 28335bf6288527b177a04100585321a1266f020004aMartijn Coenen * service for this category, which will be preferred. 28452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked 28535bf6288527b177a04100585321a1266f020004aMartijn Coenen * every time what service he would like to use in this category. 28652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked 28752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * to pick a service if there is a conflict. 28852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param category The category, for example {@link #CATEGORY_PAYMENT} 28935bf6288527b177a04100585321a1266f020004aMartijn Coenen * @return the selection mode for the passed in category 29052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 29152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public int getSelectionModeForCategory(String category) { 29252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (CATEGORY_PAYMENT.equals(category)) { 29352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(), 29452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT); 29552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (defaultComponent != null) { 29652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return SELECTION_MODE_PREFER_DEFAULT; 29752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } else { 29852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return SELECTION_MODE_ALWAYS_ASK; 29952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 30052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } else { 30152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return SELECTION_MODE_ASK_IF_CONFLICT; 30252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 30352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 30452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 30552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 306df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * Registers a list of AIDs for a specific category for the 307df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * specified service. 308aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 309df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * <p>If a list of AIDs for that category was previously 310aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * registered for this service (either statically 311aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * through the manifest, or dynamically by using this API), 312df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * that list of AIDs will be replaced with this one. 313aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 314aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * <p>Note that you can only register AIDs for a service that 3152f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * is running under the same UID as the caller of this API. Typically 316aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * this means you need to call this from the same 317aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * package as the service itself, though UIDs can also 318aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * be shared between packages using shared UIDs. 319aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 320aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * @param service The component name of the service 321df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * @param category The category of AIDs to be registered 322df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * @param aids A list containing the AIDs to be registered 323aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * @return whether the registration was successful. 324aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen */ 325df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen public boolean registerAidsForService(ComponentName service, String category, 326df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen List<String> aids) { 327df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen AidGroup aidGroup = new AidGroup(aids, category); 328aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen try { 329aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return sService.registerAidGroupForService(UserHandle.myUserId(), service, aidGroup); 330aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } catch (RemoteException e) { 331aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen // Try one more time 332aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen recoverService(); 333aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen if (sService == null) { 334aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 335aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return false; 336aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 337aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen try { 338aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return sService.registerAidGroupForService(UserHandle.myUserId(), service, 339aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen aidGroup); 340aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } catch (RemoteException ee) { 341aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 342aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return false; 343aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 344aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 345aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 346aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen 347aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen /** 348df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * Retrieves the currently registered AIDs for the specified 349aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * category for a service. 350aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 351df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * <p>Note that this will only return AIDs that were dynamically 352df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * registered using {@link #registerAidsForService(ComponentName, String, List)} 353df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * method. It will *not* return AIDs that were statically registered 354aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * in the manifest. 355aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 356aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * @param service The component name of the service 357df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * @param category The category for which the AIDs were registered, 358df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * e.g. {@link #CATEGORY_PAYMENT} 359df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * @return The list of AIDs registered for this category, or null if it couldn't be found. 360aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen */ 361df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen public List<String> getAidsForService(ComponentName service, String category) { 362aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen try { 363df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen AidGroup group = sService.getAidGroupForService(UserHandle.myUserId(), service, 364df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen category); 365df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen return (group != null ? group.getAids() : null); 366aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } catch (RemoteException e) { 367aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen recoverService(); 368aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen if (sService == null) { 369aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 370aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return null; 371aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 372aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen try { 373df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen AidGroup group = sService.getAidGroupForService(UserHandle.myUserId(), service, 374df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen category); 375df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen return (group != null ? group.getAids() : null); 376aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } catch (RemoteException ee) { 377aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 378aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return null; 379aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 380aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 381aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 382aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen 383aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen /** 384df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * Removes a previously registered list of AIDs for the specified category for the 385aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * service provided. 386aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 387df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * <p>Note that this will only remove AIDs that were dynamically 388df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * registered using the {@link #registerAidsForService(ComponentName, String, List)} 389df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * method. It will *not* remove AIDs that were statically registered in 390df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * the manifest. If dynamically registered AIDs are removed using 391aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * this method, and a statically registered AID group for the same category 3922f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * exists in the manifest, the static AID group will become active again. 393aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * 394aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * @param service The component name of the service 395df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * @param category The category of the AIDs to be removed, e.g. {@link #CATEGORY_PAYMENT} 396aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen * @return whether the group was successfully removed. 397aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen */ 398df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen public boolean removeAidsForService(ComponentName service, String category) { 399aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen try { 400aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return sService.removeAidGroupForService(UserHandle.myUserId(), service, category); 401aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } catch (RemoteException e) { 402aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen // Try one more time 403aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen recoverService(); 404aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen if (sService == null) { 405aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 406aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return false; 407aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 408aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen try { 409aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return sService.removeAidGroupForService(UserHandle.myUserId(), service, category); 410aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } catch (RemoteException ee) { 411aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 412aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen return false; 413aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 414aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 415aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen } 416aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen 417aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen /** 4182f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * Allows a foreground application to specify which card emulation service 4192f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * should be preferred while a specific Activity is in the foreground. 4202f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4212f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p>The specified Activity must currently be in resumed state. A good 4222f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * paradigm is to call this method in your {@link Activity#onResume}, and to call 4232f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}. 4242f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4252f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p>This method call will fail in two specific scenarios: 4262f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <ul> 4272f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT} 4282f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * category, but the user has indicated that foreground apps are not allowed 4292f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * to override the default payment service. 4302f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER} 4312f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * category that are also handled by the default payment service, and the 4322f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * user has indicated that foreground apps are not allowed to override the 4332f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * default payment service. 4342f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * </ul> 4352f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4362f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine 4372f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * whether foreground apps can override the default payment service. 4382f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4392f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p>Note that this preference is not persisted by the OS, and hence must be 4402f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * called every time the Activity is resumed. 4412f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4422f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @param activity The activity which prefers this service to be invoked 4432f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @param service The service to be preferred while this activity is in the foreground 4442f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @return whether the registration was successful 4452f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen */ 4462f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen public boolean setPreferredService(Activity activity, ComponentName service) { 4472f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen // Verify the activity is in the foreground before calling into NfcService 4482f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (activity == null || service == null) { 4492f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen throw new NullPointerException("activity or service or category is null"); 4502f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4512f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (!activity.isResumed()) { 4522f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen throw new IllegalArgumentException("Activity must be resumed."); 4532f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4542f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen try { 4552f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return sService.setPreferredService(service); 4562f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } catch (RemoteException e) { 4572f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen // Try one more time 4582f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen recoverService(); 4592f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (sService == null) { 4602f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 4612f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return false; 4622f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4632f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen try { 4642f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return sService.setPreferredService(service); 4652f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } catch (RemoteException ee) { 4662f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 4672f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return false; 4682f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4692f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4702f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4712f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen 4722f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen /** 4732f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * Unsets the preferred service for the specified Activity. 4742f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4752f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p>Note that the specified Activity must still be in resumed 4762f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * state at the time of this call. A good place to call this method 4772f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * is in your {@link Activity#onPause} implementation. 4782f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * 4792f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @param activity The activity which the service was registered for 4802f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * @return true when successful 4812f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen */ 4822f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen public boolean unsetPreferredService(Activity activity) { 4832f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (activity == null) { 4842f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen throw new NullPointerException("activity is null"); 4852f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4862f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (!activity.isResumed()) { 4872f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen throw new IllegalArgumentException("Activity must be resumed."); 4882f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4892f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen try { 4902f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return sService.unsetPreferredService(); 4912f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } catch (RemoteException e) { 4922f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen // Try one more time 4932f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen recoverService(); 4942f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen if (sService == null) { 4952f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 4962f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return false; 4972f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 4982f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen try { 4992f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return sService.unsetPreferredService(); 5002f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } catch (RemoteException ee) { 5012f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 5022f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen return false; 5032f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 5042f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 5052f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen } 5062f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen 5072f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen /** 508d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * Some devices may allow an application to register all 509d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * AIDs that starts with a certain prefix, e.g. 510d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * "A000000004*" to register all MasterCard AIDs. 511d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * 512d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * Use this method to determine whether this device 513d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * supports registering AID prefixes. 514d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * 515d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen * @return whether AID prefix registering is supported on this device. 516d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen */ 517d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen public boolean supportsAidPrefixRegistration() { 518826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen try { 519826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen return sService.supportsAidPrefixRegistration(); 520826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen } catch (RemoteException e) { 521826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen recoverService(); 522826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen if (sService == null) { 523826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 524826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen return false; 525826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen } 526826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen try { 527826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen return sService.supportsAidPrefixRegistration(); 528826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen } catch (RemoteException ee) { 529826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 530826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen return false; 531826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen } 532826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen } 533d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen } 534d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen 535d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen /** 53652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @hide 53752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 53852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean setDefaultServiceForCategory(ComponentName service, String category) { 53952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 54052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category); 54152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 54252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 54352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 54452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 54552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 54652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 54752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 54852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 54952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, 55052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen category); 55152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 55252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 55352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 55452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 55552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 55652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 55752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 55852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 55952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @hide 56052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 56152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean setDefaultForNextTap(ComponentName service) { 56252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 56352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultForNextTap(UserHandle.myUserId(), service); 56452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 56552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 56652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 56752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 56852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 56952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 57052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 57152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 57252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultForNextTap(UserHandle.myUserId(), service); 57352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 57452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 57552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 57652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 57752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 57852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 57935bf6288527b177a04100585321a1266f020004aMartijn Coenen 58052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 58152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @hide 58252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 58352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public List<ApduServiceInfo> getServices(String category) { 58452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 58552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.getServices(UserHandle.myUserId(), category); 58652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 58752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 58852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 58952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 59052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 59152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return null; 59252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 59352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 59452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.getServices(UserHandle.myUserId(), category); 59552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 59652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 59752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return null; 59852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 59952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 60052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 60152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 602b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen /** 603b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * A valid AID according to ISO/IEC 7816-4: 604b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * <ul> 605b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars) 606b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * <li>Consist of only hex characters 607b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * <li>Additionally, we allow an asterisk at the end, to indicate 608b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * a prefix 609b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * </ul> 610b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * 611b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen * @hide 612b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen */ 613b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen public static boolean isValidAid(String aid) { 614b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen if (aid == null) 615b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen return false; 616b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen 617b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen // If a prefix AID, the total length must be odd (even # of AID chars + '*') 618b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen if (aid.endsWith("*") && ((aid.length() % 2) == 0)) { 619b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen Log.e(TAG, "AID " + aid + " is not a valid AID."); 620b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen return false; 621b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen } 622b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen 623b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen // If not a prefix AID, the total length must be even (even # of AID chars) 624b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen if (!aid.endsWith("*") && ((aid.length() % 2) != 0)) { 625b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen Log.e(TAG, "AID " + aid + " is not a valid AID."); 626b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen return false; 627b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen } 628b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen 629b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen // Verify hex characters 630b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen if (!aid.matches("[0-9A-Fa-f]{10,32}\\*?")) { 631b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen Log.e(TAG, "AID " + aid + " is not a valid AID."); 632b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen return false; 633b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen } 634b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen 635b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen return true; 636b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen } 637b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen 63852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen void recoverService() { 63952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); 64052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sService = adapter.getCardEmulationService(); 64152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 642b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen 64352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen} 644