CardEmulation.java revision 52246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7
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; 2152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.app.ActivityThread; 2252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.ComponentName; 2352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.Context; 2452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.IPackageManager; 2552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.PackageManager; 2652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.INfcCardEmulation; 2752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.NfcAdapter; 2852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.RemoteException; 2952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.UserHandle; 3052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.provider.Settings; 3152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.util.Log; 3252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 3352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.HashMap; 3452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.List; 3552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 3652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenpublic final class CardEmulation { 3752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static final String TAG = "CardEmulation"; 3852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 3952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 4052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Activity action: ask the user to change the default 4152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * card emulation service for a certain category. This will 4252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * show a dialog that asks the user whether he wants to 4352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * replace the current default service with the service 4452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * identified with the ComponentName specified in 4552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * {@link #EXTRA_SERVICE_COMPONENT}, for the category 4652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * specified in {@link #EXTRA_CATEGORY} 4752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 4852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 4952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String ACTION_CHANGE_DEFAULT = 5052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; 5152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 5252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 5352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * The category extra for {@link #ACTION_CHANGE_DEFAULT} 5452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 5552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @see #ACTION_CHANGE_DEFAULT 5652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 5752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String EXTRA_CATEGORY = "category"; 5852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 5952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 6052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * The ComponentName object passed in as a parcelable 6152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * extra for {@link #ACTION_CHANGE_DEFAULT} 6252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 6352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @see #ACTION_CHANGE_DEFAULT 6452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 6552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String EXTRA_SERVICE_COMPONENT = "component"; 6652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 6752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 6852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * The payment category can be used to indicate that an AID 6952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * represents a payment application. 7052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 7152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String CATEGORY_PAYMENT = "payment"; 7252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 7352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 7452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * If an AID group does not contain a category, or the 7552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * specified category is not defined by the platform version 7652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * that is parsing the AID group, all AIDs in the group will 7752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * automatically be categorized under the {@link #CATEGORY_OTHER} 7852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * category. 7952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 8052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String CATEGORY_OTHER = "other"; 8152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 8252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 8352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Return value for {@link #getSelectionModeForCategory(String)}. 8452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 8552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>In this mode, the user has set a default service for this 8652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * AID category. If a remote reader selects any of the AIDs 8752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * that the default service has registered in this category, 8852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * that service will automatically be bound to to handle 8952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the transaction. 9052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 9152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>There are still cases where a service that is 9252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * not the default for a category can selected: 9352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p> 9452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * If a remote reader selects an AID in this category 9552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * that is not handled by the default service, and there is a set 9652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * of other services {S} that do handle this AID, the 9752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * user is asked if he wants to use any of the services in 9852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * {S} instead. 9952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p> 10052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * As a special case, if the size of {S} is one, containing a single service X, 10152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * and all AIDs X has registered in this category are not 10252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * registered by any other service, then X will be 10352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * selected automatically without asking the user. 10452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>Example: 10552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <ul> 10652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <li>Service A registers AIDs "1", "2" and "3" in the category 10752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <li>Service B registers AIDs "3" and "4" in the category 10852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <li>Service C registers AIDs "5" and "6" in the category 10952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * </ul> 11052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * In this case, the following will happen when service A 11152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * is the default: 11252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <ul> 11352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <li>Reader selects AID "1", "2" or "3": service A is invoked automatically 11452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <li>Reader selects AID "4": the user is asked to confirm he 11552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * wants to use service B, because its AIDs overlap with service A. 11652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <li>Reader selects AID "5" or "6": service C is invoked automatically, 11752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * because all AIDs it has asked for are only registered by C, 11852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * and there is no overlap. 11952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * </ul> 12052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 12152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 12252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final int SELECTION_MODE_PREFER_DEFAULT = 0; 12352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 12452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 12552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Return value for {@link #getSelectionModeForCategory(String)}. 12652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 12752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>In this mode, whenever an AID of this category is selected, 12852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the user is asked which service he wants to use to handle 12952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the transaction, even if there is only one matching service. 13052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 13152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final int SELECTION_MODE_ALWAYS_ASK = 1; 13252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 13352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 13452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Return value for {@link #getSelectionModeForCategory(String)}. 13552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 13652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>In this mode, the user will only be asked to select a service 13752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * if the selected AID has been registered by multiple applications. 13852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 13952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; 14052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 14152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static boolean sIsInitialized = false; 14252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static HashMap<Context, CardEmulation> sCardEmus = new HashMap(); 14352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen static INfcCardEmulation sService; 14452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 14552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen final Context mContext; 14652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 14752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen private CardEmulation(Context context, INfcCardEmulation service) { 14852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen mContext = context.getApplicationContext(); 14952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sService = service; 15052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 15152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 15252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static synchronized CardEmulation getInstance(NfcAdapter adapter) { 15352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (adapter == null) throw new NullPointerException("NfcAdapter is null"); 15452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Context context = adapter.getContext(); 15552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (context == null) { 15652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "NfcAdapter context is null."); 15752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 15852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 15952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (!sIsInitialized) { 16052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen IPackageManager pm = ActivityThread.getPackageManager(); 16152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (pm == null) { 16252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Cannot get PackageManager"); 16352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 16452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 16552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 16652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) { 16752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "This device does not support card emulation"); 16852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 16952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 17052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 17152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "PackageManager query failed."); 17252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen throw new UnsupportedOperationException(); 17352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 17452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sIsInitialized = true; 17552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 17652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen CardEmulation manager = sCardEmus.get(context); 17752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (manager == null) { 17852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Get card emu service 17952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen INfcCardEmulation service = adapter.getCardEmulationService(); 18052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen manager = new CardEmulation(context, service); 18152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sCardEmus.put(context, manager); 18252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 18352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return manager; 18452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 18552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 18652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 18752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Allows an application to query whether a service is currently 18852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the default service to handle a card emulation category. 18952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 19052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>Note that if {@link #getSelectionModeForCategory(String)} 19152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always 19252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * return false. 19352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 19452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param service The ComponentName of the service 19552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param category The category 19652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @return whether service is currently the default service for the category. 19752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 19852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean isDefaultServiceForCategory(ComponentName service, String category) { 19952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 20052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category); 20152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 20252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 20352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 20452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 20552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 20652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 20752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 20852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 20952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, 21052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen category); 21152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 21252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 21352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 21452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 21552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 21652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 21752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 21852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 21952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 22052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Allows an application to query whether a service is currently 22152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * the default handler for a specified ISO7816-4 Application ID. 22252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * 22352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param service The ComponentName of the service 22452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param aid The ISO7816-4 Application ID 22552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @return 22652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 22752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean isDefaultServiceForAid(ComponentName service, String aid) { 22852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 22952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid); 23052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 23152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 23252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 23352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 23452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 23552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 23652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 23752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 23852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid); 23952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 24052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 24152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 24252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 24352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 24452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 24552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 24652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 24752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Returns the application selection mode for the passed in category. 24852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Valid return values are: 24952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default 25052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * application for this category, which will be preferred. 25152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked 25252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * every time what app he would like to use in this category. 25352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked 25452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * to pick a service if there is a conflict. 25552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @param category The category, for example {@link #CATEGORY_PAYMENT} 25652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @return 25752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 25852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public int getSelectionModeForCategory(String category) { 25952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (CATEGORY_PAYMENT.equals(category)) { 26052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(), 26152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT); 26252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (defaultComponent != null) { 26352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return SELECTION_MODE_PREFER_DEFAULT; 26452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } else { 26552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return SELECTION_MODE_ALWAYS_ASK; 26652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 26752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } else { 26852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // All other categories are in "only ask if conflict" mode 26952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return SELECTION_MODE_ASK_IF_CONFLICT; 27052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 27152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 27252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 27352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 27452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @hide 27552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 27652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean setDefaultServiceForCategory(ComponentName service, String category) { 27752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 27852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category); 27952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 28052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 28152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 28252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 28352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 28452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 28552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 28652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 28752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, 28852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen category); 28952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 29052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 29152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 29252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 29352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 29452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 29552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 29652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 29752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @hide 29852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 29952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public boolean setDefaultForNextTap(ComponentName service) { 30052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 30152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultForNextTap(UserHandle.myUserId(), service); 30252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 30352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 30452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 30552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 30652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 30752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 30852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 30952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 31052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.setDefaultForNextTap(UserHandle.myUserId(), service); 31152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 31252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 31352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return false; 31452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 31552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 31652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 31752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 31852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * @hide 31952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 32052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public List<ApduServiceInfo> getServices(String category) { 32152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 32252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.getServices(UserHandle.myUserId(), category); 32352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException e) { 32452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen // Try one more time 32552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen recoverService(); 32652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen if (sService == null) { 32752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to recover CardEmulationService."); 32852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return null; 32952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 33052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen try { 33152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return sService.getServices(UserHandle.myUserId(), category); 33252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } catch (RemoteException ee) { 33352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen Log.e(TAG, "Failed to reach CardEmulationService."); 33452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen return null; 33552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 33652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 33752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 33852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 33952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen void recoverService() { 34052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); 34152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen sService = adapter.getCardEmulationService(); 34252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen } 34352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen} 344