1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.nfc.cardemulation; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SdkConstant; 23 import android.annotation.SdkConstant.SdkConstantType; 24 import android.app.Activity; 25 import android.app.ActivityThread; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.pm.IPackageManager; 29 import android.content.pm.PackageManager; 30 import android.nfc.INfcCardEmulation; 31 import android.nfc.NfcAdapter; 32 import android.os.RemoteException; 33 import android.provider.Settings; 34 import android.provider.Settings.SettingNotFoundException; 35 import android.util.Log; 36 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.regex.Pattern; 40 41 /** 42 * This class can be used to query the state of 43 * NFC card emulation services. 44 * 45 * For a general introduction into NFC card emulation, 46 * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html"> 47 * NFC card emulation developer guide</a>.</p> 48 * 49 * <p class="note">Use of this class requires the 50 * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present 51 * on the device. 52 */ 53 public final class CardEmulation { 54 private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); 55 static final String TAG = "CardEmulation"; 56 57 /** 58 * Activity action: ask the user to change the default 59 * card emulation service for a certain category. This will 60 * show a dialog that asks the user whether they want to 61 * replace the current default service with the service 62 * identified with the ComponentName specified in 63 * {@link #EXTRA_SERVICE_COMPONENT}, for the category 64 * specified in {@link #EXTRA_CATEGORY} 65 */ 66 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 67 public static final String ACTION_CHANGE_DEFAULT = 68 "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; 69 70 /** 71 * The category extra for {@link #ACTION_CHANGE_DEFAULT}. 72 * 73 * @see #ACTION_CHANGE_DEFAULT 74 */ 75 public static final String EXTRA_CATEGORY = "category"; 76 77 /** 78 * The service {@link ComponentName} object passed in as an 79 * extra for {@link #ACTION_CHANGE_DEFAULT}. 80 * 81 * @see #ACTION_CHANGE_DEFAULT 82 */ 83 public static final String EXTRA_SERVICE_COMPONENT = "component"; 84 85 /** 86 * Category used for NFC payment services. 87 */ 88 public static final String CATEGORY_PAYMENT = "payment"; 89 90 /** 91 * Category that can be used for all other card emulation 92 * services. 93 */ 94 public static final String CATEGORY_OTHER = "other"; 95 96 /** 97 * Return value for {@link #getSelectionModeForCategory(String)}. 98 * 99 * <p>In this mode, the user has set a default service for this 100 * category. 101 * 102 * <p>When using ISO-DEP card emulation with {@link HostApduService} 103 * or {@link OffHostApduService}, if a remote NFC device selects 104 * any of the Application IDs (AIDs) 105 * that the default service has registered in this category, 106 * that service will automatically be bound to to handle 107 * the transaction. 108 */ 109 public static final int SELECTION_MODE_PREFER_DEFAULT = 0; 110 111 /** 112 * Return value for {@link #getSelectionModeForCategory(String)}. 113 * 114 * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService} 115 * or {@link OffHostApduService}, whenever an Application ID (AID) of this category 116 * is selected, the user is asked which service they want to use to handle 117 * the transaction, even if there is only one matching service. 118 */ 119 public static final int SELECTION_MODE_ALWAYS_ASK = 1; 120 121 /** 122 * Return value for {@link #getSelectionModeForCategory(String)}. 123 * 124 * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService} 125 * or {@link OffHostApduService}, the user will only be asked to select a service 126 * if the Application ID (AID) selected by the reader has been registered by multiple 127 * services. If there is only one service that has registered for the AID, 128 * that service will be invoked directly. 129 */ 130 public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; 131 132 static boolean sIsInitialized = false; 133 static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>(); 134 static INfcCardEmulation sService; 135 136 final Context mContext; 137 CardEmulation(Context context, INfcCardEmulation service)138 private CardEmulation(Context context, INfcCardEmulation service) { 139 mContext = context.getApplicationContext(); 140 sService = service; 141 } 142 143 /** 144 * Helper to get an instance of this class. 145 * 146 * @param adapter A reference to an NfcAdapter object. 147 * @return 148 */ getInstance(NfcAdapter adapter)149 public static synchronized CardEmulation getInstance(NfcAdapter adapter) { 150 if (adapter == null) throw new NullPointerException("NfcAdapter is null"); 151 Context context = adapter.getContext(); 152 if (context == null) { 153 Log.e(TAG, "NfcAdapter context is null."); 154 throw new UnsupportedOperationException(); 155 } 156 if (!sIsInitialized) { 157 IPackageManager pm = ActivityThread.getPackageManager(); 158 if (pm == null) { 159 Log.e(TAG, "Cannot get PackageManager"); 160 throw new UnsupportedOperationException(); 161 } 162 try { 163 if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) { 164 Log.e(TAG, "This device does not support card emulation"); 165 throw new UnsupportedOperationException(); 166 } 167 } catch (RemoteException e) { 168 Log.e(TAG, "PackageManager query failed."); 169 throw new UnsupportedOperationException(); 170 } 171 sIsInitialized = true; 172 } 173 CardEmulation manager = sCardEmus.get(context); 174 if (manager == null) { 175 // Get card emu service 176 INfcCardEmulation service = adapter.getCardEmulationService(); 177 if (service == null) { 178 Log.e(TAG, "This device does not implement the INfcCardEmulation interface."); 179 throw new UnsupportedOperationException(); 180 } 181 manager = new CardEmulation(context, service); 182 sCardEmus.put(context, manager); 183 } 184 return manager; 185 } 186 187 /** 188 * Allows an application to query whether a service is currently 189 * the default service to handle a card emulation category. 190 * 191 * <p>Note that if {@link #getSelectionModeForCategory(String)} 192 * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT}, 193 * this method will always return false. That is because in these 194 * selection modes a default can't be set at the category level. For categories where 195 * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or 196 * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use 197 * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service 198 * is the default for a specific AID. 199 * 200 * @param service The ComponentName of the service 201 * @param category The category 202 * @return whether service is currently the default service for the category. 203 * 204 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 205 */ isDefaultServiceForCategory(ComponentName service, String category)206 public boolean isDefaultServiceForCategory(ComponentName service, String category) { 207 try { 208 return sService.isDefaultServiceForCategory(mContext.getUserId(), service, category); 209 } catch (RemoteException e) { 210 // Try one more time 211 recoverService(); 212 if (sService == null) { 213 Log.e(TAG, "Failed to recover CardEmulationService."); 214 return false; 215 } 216 try { 217 return sService.isDefaultServiceForCategory(mContext.getUserId(), service, 218 category); 219 } catch (RemoteException ee) { 220 Log.e(TAG, "Failed to recover CardEmulationService."); 221 return false; 222 } 223 } 224 } 225 226 /** 227 * 228 * Allows an application to query whether a service is currently 229 * the default handler for a specified ISO7816-4 Application ID. 230 * 231 * @param service The ComponentName of the service 232 * @param aid The ISO7816-4 Application ID 233 * @return whether the service is the default handler for the specified AID 234 * 235 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 236 */ isDefaultServiceForAid(ComponentName service, String aid)237 public boolean isDefaultServiceForAid(ComponentName service, String aid) { 238 try { 239 return sService.isDefaultServiceForAid(mContext.getUserId(), service, aid); 240 } catch (RemoteException e) { 241 // Try one more time 242 recoverService(); 243 if (sService == null) { 244 Log.e(TAG, "Failed to recover CardEmulationService."); 245 return false; 246 } 247 try { 248 return sService.isDefaultServiceForAid(mContext.getUserId(), service, aid); 249 } catch (RemoteException ee) { 250 Log.e(TAG, "Failed to reach CardEmulationService."); 251 return false; 252 } 253 } 254 } 255 256 /** 257 * Returns whether the user has allowed AIDs registered in the 258 * specified category to be handled by a service that is preferred 259 * by the foreground application, instead of by a pre-configured default. 260 * 261 * Foreground applications can set such preferences using the 262 * {@link #setPreferredService(Activity, ComponentName)} method. 263 * 264 * @param category The category, e.g. {@link #CATEGORY_PAYMENT} 265 * @return whether AIDs in the category can be handled by a service 266 * specified by the foreground app. 267 */ categoryAllowsForegroundPreference(String category)268 public boolean categoryAllowsForegroundPreference(String category) { 269 if (CATEGORY_PAYMENT.equals(category)) { 270 boolean preferForeground = false; 271 try { 272 preferForeground = Settings.Secure.getInt(mContext.getContentResolver(), 273 Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0; 274 } catch (SettingNotFoundException e) { 275 } 276 return preferForeground; 277 } else { 278 // Allowed for all other categories 279 return true; 280 } 281 } 282 283 /** 284 * Returns the service selection mode for the passed in category. 285 * Valid return values are: 286 * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default 287 * service for this category, which will be preferred. 288 * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked 289 * every time what service they would like to use in this category. 290 * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked 291 * to pick a service if there is a conflict. 292 * @param category The category, for example {@link #CATEGORY_PAYMENT} 293 * @return the selection mode for the passed in category 294 */ getSelectionModeForCategory(String category)295 public int getSelectionModeForCategory(String category) { 296 if (CATEGORY_PAYMENT.equals(category)) { 297 boolean paymentRegistered = false; 298 try { 299 paymentRegistered = sService.isDefaultPaymentRegistered(); 300 } catch (RemoteException e) { 301 recoverService(); 302 if (sService == null) { 303 Log.e(TAG, "Failed to recover CardEmulationService."); 304 return SELECTION_MODE_ALWAYS_ASK; 305 } 306 try { 307 paymentRegistered = sService.isDefaultPaymentRegistered(); 308 } catch (RemoteException ee) { 309 Log.e(TAG, "Failed to reach CardEmulationService."); 310 return SELECTION_MODE_ALWAYS_ASK; 311 } 312 } 313 if (paymentRegistered) { 314 return SELECTION_MODE_PREFER_DEFAULT; 315 } else { 316 return SELECTION_MODE_ALWAYS_ASK; 317 } 318 } else { 319 return SELECTION_MODE_ASK_IF_CONFLICT; 320 } 321 } 322 323 /** 324 * Registers a list of AIDs for a specific category for the 325 * specified service. 326 * 327 * <p>If a list of AIDs for that category was previously 328 * registered for this service (either statically 329 * through the manifest, or dynamically by using this API), 330 * that list of AIDs will be replaced with this one. 331 * 332 * <p>Note that you can only register AIDs for a service that 333 * is running under the same UID as the caller of this API. Typically 334 * this means you need to call this from the same 335 * package as the service itself, though UIDs can also 336 * be shared between packages using shared UIDs. 337 * 338 * @param service The component name of the service 339 * @param category The category of AIDs to be registered 340 * @param aids A list containing the AIDs to be registered 341 * @return whether the registration was successful. 342 */ registerAidsForService(ComponentName service, String category, List<String> aids)343 public boolean registerAidsForService(ComponentName service, String category, 344 List<String> aids) { 345 AidGroup aidGroup = new AidGroup(aids, category); 346 try { 347 return sService.registerAidGroupForService(mContext.getUserId(), service, aidGroup); 348 } catch (RemoteException e) { 349 // Try one more time 350 recoverService(); 351 if (sService == null) { 352 Log.e(TAG, "Failed to recover CardEmulationService."); 353 return false; 354 } 355 try { 356 return sService.registerAidGroupForService(mContext.getUserId(), service, 357 aidGroup); 358 } catch (RemoteException ee) { 359 Log.e(TAG, "Failed to reach CardEmulationService."); 360 return false; 361 } 362 } 363 } 364 365 /** 366 * Unsets the off-host Secure Element for the given service. 367 * 368 * <p>Note that this will only remove Secure Element that was dynamically 369 * set using the {@link #setOffHostForService(ComponentName, String)} 370 * and resets it to a value that was statically assigned using manifest. 371 * 372 * <p>Note that you can only unset off-host SE for a service that 373 * is running under the same UID as the caller of this API. Typically 374 * this means you need to call this from the same 375 * package as the service itself, though UIDs can also 376 * be shared between packages using shared UIDs. 377 * 378 * @param service The component name of the service 379 * @return whether the registration was successful. 380 */ 381 @RequiresPermission(android.Manifest.permission.NFC) 382 @NonNull unsetOffHostForService(@onNull ComponentName service)383 public boolean unsetOffHostForService(@NonNull ComponentName service) { 384 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); 385 if (adapter == null) { 386 return false; 387 } 388 389 try { 390 return sService.unsetOffHostForService(mContext.getUserId(), service); 391 } catch (RemoteException e) { 392 // Try one more time 393 recoverService(); 394 if (sService == null) { 395 Log.e(TAG, "Failed to recover CardEmulationService."); 396 return false; 397 } 398 try { 399 return sService.unsetOffHostForService(mContext.getUserId(), service); 400 } catch (RemoteException ee) { 401 Log.e(TAG, "Failed to reach CardEmulationService."); 402 return false; 403 } 404 } 405 } 406 407 /** 408 * Sets the off-host Secure Element for the given service. 409 * 410 * <p>If off-host SE was initially set (either statically 411 * through the manifest, or dynamically by using this API), 412 * it will be replaced with this one. All AIDs registered by 413 * this service will be re-routed to this Secure Element if 414 * successful. AIDs that was statically assigned using manifest 415 * will re-route to off-host SE that stated in manifest after NFC 416 * toggle. 417 * 418 * <p>Note that you can only set off-host SE for a service that 419 * is running under the same UID as the caller of this API. Typically 420 * this means you need to call this from the same 421 * package as the service itself, though UIDs can also 422 * be shared between packages using shared UIDs. 423 * 424 * <p>Registeration will be successful only if the Secure Element 425 * exists on the device. 426 * 427 * @param service The component name of the service 428 * @param offHostSecureElement Secure Element to register the AID to. Only accept strings with 429 * prefix SIM or prefix eSE. 430 * Ref: GSMA TS.26 - NFC Handset Requirements 431 * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be 432 * SIM[smartcard slot] 433 * (e.g. SIM/SIM1, SIM2… SIMn). 434 * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be 435 * eSE[number] 436 * (e.g. eSE/eSE1, eSE2, etc.). 437 * @return whether the registration was successful. 438 */ 439 @RequiresPermission(android.Manifest.permission.NFC) 440 @NonNull setOffHostForService(@onNull ComponentName service, @NonNull String offHostSecureElement)441 public boolean setOffHostForService(@NonNull ComponentName service, 442 @NonNull String offHostSecureElement) { 443 boolean validSecureElement = false; 444 445 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); 446 if (adapter == null || offHostSecureElement == null) { 447 return false; 448 } 449 450 List<String> validSE = adapter.getSupportedOffHostSecureElements(); 451 if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE")) 452 || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) { 453 return false; 454 } 455 456 if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")) { 457 return false; 458 } 459 460 if (offHostSecureElement.equals("eSE")) { 461 offHostSecureElement = "eSE1"; 462 } else if (offHostSecureElement.equals("SIM")) { 463 offHostSecureElement = "SIM1"; 464 } 465 466 try { 467 return sService.setOffHostForService(mContext.getUserId(), service, 468 offHostSecureElement); 469 } catch (RemoteException e) { 470 // Try one more time 471 recoverService(); 472 if (sService == null) { 473 Log.e(TAG, "Failed to recover CardEmulationService."); 474 return false; 475 } 476 try { 477 return sService.setOffHostForService(mContext.getUserId(), service, 478 offHostSecureElement); 479 } catch (RemoteException ee) { 480 Log.e(TAG, "Failed to reach CardEmulationService."); 481 return false; 482 } 483 } 484 } 485 486 /** 487 * Retrieves the currently registered AIDs for the specified 488 * category for a service. 489 * 490 * <p>Note that this will only return AIDs that were dynamically 491 * registered using {@link #registerAidsForService(ComponentName, String, List)} 492 * method. It will *not* return AIDs that were statically registered 493 * in the manifest. 494 * 495 * @param service The component name of the service 496 * @param category The category for which the AIDs were registered, 497 * e.g. {@link #CATEGORY_PAYMENT} 498 * @return The list of AIDs registered for this category, or null if it couldn't be found. 499 */ getAidsForService(ComponentName service, String category)500 public List<String> getAidsForService(ComponentName service, String category) { 501 try { 502 AidGroup group = sService.getAidGroupForService(mContext.getUserId(), service, 503 category); 504 return (group != null ? group.getAids() : null); 505 } catch (RemoteException e) { 506 recoverService(); 507 if (sService == null) { 508 Log.e(TAG, "Failed to recover CardEmulationService."); 509 return null; 510 } 511 try { 512 AidGroup group = sService.getAidGroupForService(mContext.getUserId(), service, 513 category); 514 return (group != null ? group.getAids() : null); 515 } catch (RemoteException ee) { 516 Log.e(TAG, "Failed to recover CardEmulationService."); 517 return null; 518 } 519 } 520 } 521 522 /** 523 * Removes a previously registered list of AIDs for the specified category for the 524 * service provided. 525 * 526 * <p>Note that this will only remove AIDs that were dynamically 527 * registered using the {@link #registerAidsForService(ComponentName, String, List)} 528 * method. It will *not* remove AIDs that were statically registered in 529 * the manifest. If dynamically registered AIDs are removed using 530 * this method, and a statically registered AID group for the same category 531 * exists in the manifest, the static AID group will become active again. 532 * 533 * @param service The component name of the service 534 * @param category The category of the AIDs to be removed, e.g. {@link #CATEGORY_PAYMENT} 535 * @return whether the group was successfully removed. 536 */ removeAidsForService(ComponentName service, String category)537 public boolean removeAidsForService(ComponentName service, String category) { 538 try { 539 return sService.removeAidGroupForService(mContext.getUserId(), service, category); 540 } catch (RemoteException e) { 541 // Try one more time 542 recoverService(); 543 if (sService == null) { 544 Log.e(TAG, "Failed to recover CardEmulationService."); 545 return false; 546 } 547 try { 548 return sService.removeAidGroupForService(mContext.getUserId(), service, category); 549 } catch (RemoteException ee) { 550 Log.e(TAG, "Failed to reach CardEmulationService."); 551 return false; 552 } 553 } 554 } 555 556 /** 557 * Allows a foreground application to specify which card emulation service 558 * should be preferred while a specific Activity is in the foreground. 559 * 560 * <p>The specified Activity must currently be in resumed state. A good 561 * paradigm is to call this method in your {@link Activity#onResume}, and to call 562 * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}. 563 * 564 * <p>This method call will fail in two specific scenarios: 565 * <ul> 566 * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT} 567 * category, but the user has indicated that foreground apps are not allowed 568 * to override the default payment service. 569 * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER} 570 * category that are also handled by the default payment service, and the 571 * user has indicated that foreground apps are not allowed to override the 572 * default payment service. 573 * </ul> 574 * 575 * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine 576 * whether foreground apps can override the default payment service. 577 * 578 * <p>Note that this preference is not persisted by the OS, and hence must be 579 * called every time the Activity is resumed. 580 * 581 * @param activity The activity which prefers this service to be invoked 582 * @param service The service to be preferred while this activity is in the foreground 583 * @return whether the registration was successful 584 */ setPreferredService(Activity activity, ComponentName service)585 public boolean setPreferredService(Activity activity, ComponentName service) { 586 // Verify the activity is in the foreground before calling into NfcService 587 if (activity == null || service == null) { 588 throw new NullPointerException("activity or service or category is null"); 589 } 590 if (!activity.isResumed()) { 591 throw new IllegalArgumentException("Activity must be resumed."); 592 } 593 try { 594 return sService.setPreferredService(service); 595 } catch (RemoteException e) { 596 // Try one more time 597 recoverService(); 598 if (sService == null) { 599 Log.e(TAG, "Failed to recover CardEmulationService."); 600 return false; 601 } 602 try { 603 return sService.setPreferredService(service); 604 } catch (RemoteException ee) { 605 Log.e(TAG, "Failed to reach CardEmulationService."); 606 return false; 607 } 608 } 609 } 610 611 /** 612 * Unsets the preferred service for the specified Activity. 613 * 614 * <p>Note that the specified Activity must still be in resumed 615 * state at the time of this call. A good place to call this method 616 * is in your {@link Activity#onPause} implementation. 617 * 618 * @param activity The activity which the service was registered for 619 * @return true when successful 620 */ unsetPreferredService(Activity activity)621 public boolean unsetPreferredService(Activity activity) { 622 if (activity == null) { 623 throw new NullPointerException("activity is null"); 624 } 625 if (!activity.isResumed()) { 626 throw new IllegalArgumentException("Activity must be resumed."); 627 } 628 try { 629 return sService.unsetPreferredService(); 630 } catch (RemoteException e) { 631 // Try one more time 632 recoverService(); 633 if (sService == null) { 634 Log.e(TAG, "Failed to recover CardEmulationService."); 635 return false; 636 } 637 try { 638 return sService.unsetPreferredService(); 639 } catch (RemoteException ee) { 640 Log.e(TAG, "Failed to reach CardEmulationService."); 641 return false; 642 } 643 } 644 } 645 646 /** 647 * Some devices may allow an application to register all 648 * AIDs that starts with a certain prefix, e.g. 649 * "A000000004*" to register all MasterCard AIDs. 650 * 651 * Use this method to determine whether this device 652 * supports registering AID prefixes. 653 * 654 * @return whether AID prefix registering is supported on this device. 655 */ supportsAidPrefixRegistration()656 public boolean supportsAidPrefixRegistration() { 657 try { 658 return sService.supportsAidPrefixRegistration(); 659 } catch (RemoteException e) { 660 recoverService(); 661 if (sService == null) { 662 Log.e(TAG, "Failed to recover CardEmulationService."); 663 return false; 664 } 665 try { 666 return sService.supportsAidPrefixRegistration(); 667 } catch (RemoteException ee) { 668 Log.e(TAG, "Failed to reach CardEmulationService."); 669 return false; 670 } 671 } 672 } 673 674 /** 675 * Retrieves the registered AIDs for the preferred payment service. 676 * 677 * @return The list of AIDs registered for this category, or null if it couldn't be found. 678 */ 679 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 680 @Nullable getAidsForPreferredPaymentService()681 public List<String> getAidsForPreferredPaymentService() { 682 try { 683 ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); 684 return (serviceInfo != null ? serviceInfo.getAids() : null); 685 } catch (RemoteException e) { 686 recoverService(); 687 if (sService == null) { 688 Log.e(TAG, "Failed to recover CardEmulationService."); 689 throw e.rethrowFromSystemServer(); 690 } 691 try { 692 ApduServiceInfo serviceInfo = 693 sService.getPreferredPaymentService(mContext.getUserId()); 694 return (serviceInfo != null ? serviceInfo.getAids() : null); 695 } catch (RemoteException ee) { 696 Log.e(TAG, "Failed to recover CardEmulationService."); 697 throw e.rethrowFromSystemServer(); 698 } 699 } 700 } 701 702 /** 703 * Retrieves the route destination for the preferred payment service. 704 * 705 * @return The route destination secure element name of the preferred payment service. 706 * HCE payment: "Host" 707 * OffHost payment: 1. String with prefix SIM or prefix eSE string. 708 * Ref: GSMA TS.26 - NFC Handset Requirements 709 * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be 710 * SIM[smartcard slot] 711 * (e.g. SIM/SIM1, SIM2… SIMn). 712 * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be 713 * eSE[number] 714 * (e.g. eSE/eSE1, eSE2, etc.). 715 * 2. "OffHost" if the payment service does not specify secure element 716 * name. 717 */ 718 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 719 @Nullable getRouteDestinationForPreferredPaymentService()720 public String getRouteDestinationForPreferredPaymentService() { 721 try { 722 ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); 723 if (serviceInfo != null) { 724 if (!serviceInfo.isOnHost()) { 725 return serviceInfo.getOffHostSecureElement() == null ? 726 "OffHost" : serviceInfo.getOffHostSecureElement(); 727 } 728 return "Host"; 729 } 730 return null; 731 } catch (RemoteException e) { 732 recoverService(); 733 if (sService == null) { 734 Log.e(TAG, "Failed to recover CardEmulationService."); 735 throw e.rethrowFromSystemServer(); 736 } 737 try { 738 ApduServiceInfo serviceInfo = 739 sService.getPreferredPaymentService(mContext.getUserId()); 740 if (serviceInfo != null) { 741 if (!serviceInfo.isOnHost()) { 742 return serviceInfo.getOffHostSecureElement() == null ? 743 "Offhost" : serviceInfo.getOffHostSecureElement(); 744 } 745 return "Host"; 746 } 747 return null; 748 749 } catch (RemoteException ee) { 750 Log.e(TAG, "Failed to recover CardEmulationService."); 751 throw e.rethrowFromSystemServer(); 752 } 753 } 754 } 755 756 /** 757 * Returns a user-visible description of the preferred payment service. 758 * 759 * @return the preferred payment service description 760 */ 761 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 762 @Nullable getDescriptionForPreferredPaymentService()763 public CharSequence getDescriptionForPreferredPaymentService() { 764 try { 765 ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); 766 return (serviceInfo != null ? serviceInfo.getDescription() : null); 767 } catch (RemoteException e) { 768 recoverService(); 769 if (sService == null) { 770 Log.e(TAG, "Failed to recover CardEmulationService."); 771 throw e.rethrowFromSystemServer(); 772 } 773 try { 774 ApduServiceInfo serviceInfo = 775 sService.getPreferredPaymentService(mContext.getUserId()); 776 return (serviceInfo != null ? serviceInfo.getDescription() : null); 777 } catch (RemoteException ee) { 778 Log.e(TAG, "Failed to recover CardEmulationService."); 779 throw e.rethrowFromSystemServer(); 780 } 781 } 782 } 783 784 /** 785 * @hide 786 */ setDefaultServiceForCategory(ComponentName service, String category)787 public boolean setDefaultServiceForCategory(ComponentName service, String category) { 788 try { 789 return sService.setDefaultServiceForCategory(mContext.getUserId(), service, category); 790 } catch (RemoteException e) { 791 // Try one more time 792 recoverService(); 793 if (sService == null) { 794 Log.e(TAG, "Failed to recover CardEmulationService."); 795 return false; 796 } 797 try { 798 return sService.setDefaultServiceForCategory(mContext.getUserId(), service, 799 category); 800 } catch (RemoteException ee) { 801 Log.e(TAG, "Failed to reach CardEmulationService."); 802 return false; 803 } 804 } 805 } 806 807 /** 808 * @hide 809 */ setDefaultForNextTap(ComponentName service)810 public boolean setDefaultForNextTap(ComponentName service) { 811 try { 812 return sService.setDefaultForNextTap(mContext.getUserId(), service); 813 } catch (RemoteException e) { 814 // Try one more time 815 recoverService(); 816 if (sService == null) { 817 Log.e(TAG, "Failed to recover CardEmulationService."); 818 return false; 819 } 820 try { 821 return sService.setDefaultForNextTap(mContext.getUserId(), service); 822 } catch (RemoteException ee) { 823 Log.e(TAG, "Failed to reach CardEmulationService."); 824 return false; 825 } 826 } 827 } 828 829 /** 830 * @hide 831 */ getServices(String category)832 public List<ApduServiceInfo> getServices(String category) { 833 try { 834 return sService.getServices(mContext.getUserId(), category); 835 } catch (RemoteException e) { 836 // Try one more time 837 recoverService(); 838 if (sService == null) { 839 Log.e(TAG, "Failed to recover CardEmulationService."); 840 return null; 841 } 842 try { 843 return sService.getServices(mContext.getUserId(), category); 844 } catch (RemoteException ee) { 845 Log.e(TAG, "Failed to reach CardEmulationService."); 846 return null; 847 } 848 } 849 } 850 851 /** 852 * A valid AID according to ISO/IEC 7816-4: 853 * <ul> 854 * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars) 855 * <li>Consist of only hex characters 856 * <li>Additionally, we allow an asterisk at the end, to indicate 857 * a prefix 858 * <li>Additinally we allow an (#) at symbol at the end, to indicate 859 * a subset 860 * </ul> 861 * 862 * @hide 863 */ isValidAid(String aid)864 public static boolean isValidAid(String aid) { 865 if (aid == null) 866 return false; 867 868 // If a prefix/subset AID, the total length must be odd (even # of AID chars + '*') 869 if ((aid.endsWith("*") || aid.endsWith("#")) && ((aid.length() % 2) == 0)) { 870 Log.e(TAG, "AID " + aid + " is not a valid AID."); 871 return false; 872 } 873 874 // If not a prefix/subset AID, the total length must be even (even # of AID chars) 875 if ((!(aid.endsWith("*") || aid.endsWith("#"))) && ((aid.length() % 2) != 0)) { 876 Log.e(TAG, "AID " + aid + " is not a valid AID."); 877 return false; 878 } 879 880 // Verify hex characters 881 if (!AID_PATTERN.matcher(aid).matches()) { 882 Log.e(TAG, "AID " + aid + " is not a valid AID."); 883 return false; 884 } 885 886 return true; 887 } 888 recoverService()889 void recoverService() { 890 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); 891 sService = adapter.getCardEmulationService(); 892 } 893 894 } 895