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.Manifest; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.FlaggedApi; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.RequiresFeature; 26 import android.annotation.RequiresPermission; 27 import android.annotation.SdkConstant; 28 import android.annotation.SdkConstant.SdkConstantType; 29 import android.annotation.SystemApi; 30 import android.annotation.UserHandleAware; 31 import android.annotation.UserIdInt; 32 import android.app.Activity; 33 import android.app.role.RoleManager; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.pm.PackageManager; 38 import android.nfc.ComponentNameAndUser; 39 import android.nfc.Constants; 40 import android.nfc.Flags; 41 import android.nfc.INfcCardEmulation; 42 import android.nfc.INfcEventCallback; 43 import android.nfc.NfcAdapter; 44 import android.os.Build; 45 import android.os.Handler; 46 import android.os.IBinder; 47 import android.os.Looper; 48 import android.os.RemoteException; 49 import android.os.UserHandle; 50 import android.provider.Settings; 51 import android.provider.Settings.SettingNotFoundException; 52 import android.telephony.SubscriptionManager; 53 import android.util.ArrayMap; 54 import android.util.Log; 55 56 import java.lang.annotation.Retention; 57 import java.lang.annotation.RetentionPolicy; 58 import java.util.HashMap; 59 import java.util.HexFormat; 60 import java.util.List; 61 import java.util.Locale; 62 import java.util.Objects; 63 import java.util.concurrent.Executor; 64 import java.util.regex.Pattern; 65 66 /** 67 * This class can be used to query the state of 68 * NFC card emulation services. 69 * 70 * For a general introduction into NFC card emulation, 71 * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html"> 72 * NFC card emulation developer guide</a>.</p> 73 * 74 * <p class="note">Use of this class requires the 75 * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present 76 * on the device. 77 */ 78 public final class CardEmulation { 79 // TODO(b/395959119) Get this from ApduServiceInfo so we don't have to maintain it in two code 80 // locations. 81 private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); 82 private static final Pattern PLPF_PATTERN = 83 Pattern.compile("[0-9A-Fa-f]{2,}[0-9A-Fa-f,\\?,\\*\\.]*"); 84 static final String TAG = "CardEmulation"; 85 86 /** 87 * Activity action: ask the user to change the default 88 * card emulation service for a certain category. This will 89 * show a dialog that asks the user whether they want to 90 * replace the current default service with the service 91 * identified with the ComponentName specified in 92 * {@link #EXTRA_SERVICE_COMPONENT}, for the category 93 * specified in {@link #EXTRA_CATEGORY}. There is an optional 94 * extra field using {@link Intent#EXTRA_USER} to specify 95 * the {@link UserHandle} of the user that owns the app. 96 * 97 * @deprecated Please use {@link android.app.role.RoleManager#createRequestRoleIntent(String)} 98 * with {@link android.app.role.RoleManager#ROLE_WALLET} parameter 99 * and {@link Activity#startActivityForResult(Intent, int)} instead. 100 */ 101 @Deprecated 102 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 103 public static final String ACTION_CHANGE_DEFAULT = 104 "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; 105 106 /** 107 * The category extra for {@link #ACTION_CHANGE_DEFAULT}. 108 * 109 * @see #ACTION_CHANGE_DEFAULT 110 */ 111 public static final String EXTRA_CATEGORY = "category"; 112 113 /** 114 * The service {@link ComponentName} object passed in as an 115 * extra for {@link #ACTION_CHANGE_DEFAULT}. 116 * 117 * @see #ACTION_CHANGE_DEFAULT 118 */ 119 public static final String EXTRA_SERVICE_COMPONENT = "component"; 120 121 /** 122 * Category used for NFC payment services. 123 */ 124 public static final String CATEGORY_PAYMENT = "payment"; 125 126 /** 127 * Category that can be used for all other card emulation 128 * services. 129 */ 130 public static final String CATEGORY_OTHER = "other"; 131 132 /** 133 * Return value for {@link #getSelectionModeForCategory(String)}. 134 * 135 * <p>In this mode, the user has set a default service for this 136 * category. 137 * 138 * <p>When using ISO-DEP card emulation with {@link HostApduService} 139 * or {@link OffHostApduService}, if a remote NFC device selects 140 * any of the Application IDs (AIDs) 141 * that the default service has registered in this category, 142 * that service will automatically be bound to to handle 143 * the transaction. 144 */ 145 public static final int SELECTION_MODE_PREFER_DEFAULT = 0; 146 147 /** 148 * Return value for {@link #getSelectionModeForCategory(String)}. 149 * 150 * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService} 151 * or {@link OffHostApduService}, whenever an Application ID (AID) of this category 152 * is selected, the user is asked which service they want to use to handle 153 * the transaction, even if there is only one matching service. 154 */ 155 public static final int SELECTION_MODE_ALWAYS_ASK = 1; 156 157 /** 158 * Return value for {@link #getSelectionModeForCategory(String)}. 159 * 160 * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService} 161 * or {@link OffHostApduService}, the user will only be asked to select a service 162 * if the Application ID (AID) selected by the reader has been registered by multiple 163 * services. If there is only one service that has registered for the AID, 164 * that service will be invoked directly. 165 */ 166 public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; 167 /** 168 * Route to Device Host (DH). 169 */ 170 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) 171 public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0; 172 /** 173 * Route to eSE. 174 */ 175 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) 176 public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1; 177 /** 178 * Route to UICC. 179 */ 180 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) 181 public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC = 2; 182 183 /** 184 * Route to the default value in config file. 185 */ 186 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) 187 public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; 188 189 /** 190 * Route to T4T NDEF-NCEE emulation. 191 * @see android.nfc.T4tNdefNfcee 192 */ 193 @FlaggedApi(com.android.nfc.module.flags.Flags.FLAG_OEM_EXTENSION_25Q4) 194 public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_NDEF_NFCEE = 4; 195 /** 196 * Route unset. 197 */ 198 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) 199 public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1; 200 201 /** 202 * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} 203 * succeeded. 204 * @hide 205 */ 206 @SystemApi 207 @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) 208 public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; 209 210 /** 211 * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} 212 * failed due to the unsupported feature. 213 * @hide 214 */ 215 @SystemApi 216 @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) 217 public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; 218 219 /** 220 * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} 221 * failed due to the invalid service. 222 * @hide 223 */ 224 @SystemApi 225 @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) 226 public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; 227 228 /** 229 * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} 230 * failed due to the service is already set to the requested status. 231 * @hide 232 */ 233 @SystemApi 234 @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) 235 public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; 236 237 /** 238 * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} 239 * failed due to unknown error. 240 * @hide 241 */ 242 @SystemApi 243 @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) 244 public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; 245 246 /** 247 * Status code returned by {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} 248 * @hide 249 */ 250 @IntDef(prefix = "SET_SERVICE_ENABLED_STATUS_", value = { 251 SET_SERVICE_ENABLED_STATUS_OK, 252 SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED, 253 SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE, 254 SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET, 255 SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR 256 }) 257 @Retention(RetentionPolicy.SOURCE) 258 public @interface SetServiceEnabledStatusCode {} 259 260 /** 261 * Property name used to indicate that an application wants to allow associated services 262 * to share the same AID routing priority when this application is the role holder. 263 * <p> 264 * Example: 265 * <pre> 266 * {@code 267 * <application> 268 * ... 269 * <property android:name="android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY" 270 * android:value="true"/> 271 * </application> 272 * } 273 * </pre> 274 */ 275 @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES) 276 public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY = 277 "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY"; 278 279 static boolean sIsInitialized = false; 280 static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>(); 281 static INfcCardEmulation sService; 282 283 final Context mContext; 284 CardEmulation(Context context, INfcCardEmulation service)285 private CardEmulation(Context context, INfcCardEmulation service) { 286 mContext = context.getApplicationContext(); 287 sService = service; 288 } 289 290 /** 291 * Helper to get an instance of this class. 292 * 293 * @param adapter A reference to an NfcAdapter object. 294 * @return 295 */ getInstance(NfcAdapter adapter)296 public static synchronized CardEmulation getInstance(NfcAdapter adapter) { 297 if (adapter == null) throw new NullPointerException("NfcAdapter is null"); 298 Context context = adapter.getContext(); 299 if (context == null) { 300 Log.e(TAG, "NfcAdapter context is null."); 301 throw new UnsupportedOperationException(); 302 } 303 if (!sIsInitialized) { 304 PackageManager pm = context.getPackageManager(); 305 if (pm == null) { 306 Log.e(TAG, "Cannot get PackageManager"); 307 throw new UnsupportedOperationException(); 308 } 309 if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) { 310 Log.e(TAG, "This device does not support card emulation"); 311 throw new UnsupportedOperationException(); 312 } 313 sIsInitialized = true; 314 } 315 CardEmulation manager = sCardEmus.get(context); 316 if (manager == null) { 317 // Get card emu service 318 INfcCardEmulation service = adapter.getCardEmulationService(); 319 if (service == null) { 320 Log.e(TAG, "This device does not implement the INfcCardEmulation interface."); 321 throw new UnsupportedOperationException(); 322 } 323 manager = new CardEmulation(context, service); 324 sCardEmus.put(context, manager); 325 } 326 return manager; 327 } 328 329 /** 330 * Allows an application to query whether a service is currently 331 * the default service to handle a card emulation category. 332 * 333 * <p>Note that if {@link #getSelectionModeForCategory(String)} 334 * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT}, 335 * this method will always return false. That is because in these 336 * selection modes a default can't be set at the category level. For categories where 337 * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or 338 * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use 339 * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service 340 * is the default for a specific AID. 341 * 342 * @param service The ComponentName of the service 343 * @param category The category 344 * @return whether service is currently the default service for the category. 345 * 346 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 347 */ isDefaultServiceForCategory(ComponentName service, String category)348 public boolean isDefaultServiceForCategory(ComponentName service, String category) { 349 return callServiceReturn(() -> 350 sService.isDefaultServiceForCategory( 351 mContext.getUser().getIdentifier(), service, category), false); 352 } 353 354 /** 355 * 356 * Allows an application to query whether a service is currently 357 * the default handler for a specified ISO7816-4 Application ID. 358 * 359 * @param service The ComponentName of the service 360 * @param aid The ISO7816-4 Application ID 361 * @return whether the service is the default handler for the specified AID 362 * 363 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 364 */ isDefaultServiceForAid(ComponentName service, String aid)365 public boolean isDefaultServiceForAid(ComponentName service, String aid) { 366 return callServiceReturn(() -> 367 sService.isDefaultServiceForAid( 368 mContext.getUser().getIdentifier(), service, aid), false); 369 } 370 371 /** 372 * <p> 373 * Returns whether the user has allowed AIDs registered in the 374 * specified category to be handled by a service that is preferred 375 * by the foreground application, instead of by a pre-configured default. 376 * 377 * Foreground applications can set such preferences using the 378 * {@link #setPreferredService(Activity, ComponentName)} method. 379 * <p class="note"> 380 * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, this method will always 381 * return true. 382 * 383 * @param category The category, e.g. {@link #CATEGORY_PAYMENT} 384 * @return whether AIDs in the category can be handled by a service 385 * specified by the foreground app. 386 */ 387 @SuppressWarnings("NonUserGetterCalled") categoryAllowsForegroundPreference(String category)388 public boolean categoryAllowsForegroundPreference(String category) { 389 Context contextAsUser = mContext.createContextAsUser( 390 UserHandle.of(UserHandle.myUserId()), 0); 391 392 RoleManager roleManager = contextAsUser.getSystemService(RoleManager.class); 393 if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) { 394 return true; 395 } 396 397 if (CATEGORY_PAYMENT.equals(category)) { 398 boolean preferForeground = false; 399 try { 400 preferForeground = Settings.Secure.getInt( 401 contextAsUser.getContentResolver(), 402 Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND) != 0; 403 } catch (SettingNotFoundException e) { 404 } 405 return preferForeground; 406 } else { 407 // Allowed for all other categories 408 return true; 409 } 410 } 411 412 /** 413 * Returns the service selection mode for the passed in category. 414 * Valid return values are: 415 * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default 416 * service for this category, which will be preferred. 417 * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked 418 * every time what service they would like to use in this category. 419 * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked 420 * to pick a service if there is a conflict. 421 * 422 * <p class="note"> 423 * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the default service defined 424 * by the holder of {@link android.app.role.RoleManager#ROLE_WALLET} and is category agnostic. 425 * 426 * @param category The category, for example {@link #CATEGORY_PAYMENT} 427 * @return the selection mode for the passed in category 428 */ getSelectionModeForCategory(String category)429 public int getSelectionModeForCategory(String category) { 430 if (CATEGORY_PAYMENT.equals(category)) { 431 boolean paymentRegistered = callServiceReturn(() -> 432 sService.isDefaultPaymentRegistered(), false); 433 if (paymentRegistered) { 434 return SELECTION_MODE_PREFER_DEFAULT; 435 } else { 436 return SELECTION_MODE_ALWAYS_ASK; 437 } 438 } else { 439 return SELECTION_MODE_ASK_IF_CONFLICT; 440 } 441 } 442 /** 443 * Sets whether when this service becomes the preferred service, if the NFC stack 444 * should enable observe mode or disable observe mode. The default is to not enable observe 445 * mode when a service either the foreground default service or the default payment service so 446 * not calling this method will preserve that behavior. 447 * 448 * @param service The component name of the service 449 * @param enable Whether the service should default to observe mode or not 450 * @return whether the change was successful. 451 */ setShouldDefaultToObserveModeForService(@onNull ComponentName service, boolean enable)452 public boolean setShouldDefaultToObserveModeForService(@NonNull ComponentName service, 453 boolean enable) { 454 return callServiceReturn(() -> 455 sService.setShouldDefaultToObserveModeForService( 456 mContext.getUser().getIdentifier(), service, enable), false); 457 } 458 459 /** 460 * Register a polling loop filter (PLF) for a HostApduService and indicate whether it should 461 * auto-transact or not. The PLF can be sequence of an 462 * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of 463 * bytes. When non-standard polling loop frame matches this sequence exactly, it may be 464 * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact 465 * is set to true and this service is currently preferred or there are no other services 466 * registered for this filter then observe mode will also be disabled. 467 * @param service The HostApduService to register the filter for 468 * @param pollingLoopFilter The filter to register 469 * @param autoTransact true to have the NFC stack automatically disable observe mode and allow 470 * transactions to proceed when this filter matches, false otherwise 471 * @return true if the filter was registered, false otherwise 472 * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte 473 */ registerPollingLoopFilterForService(@onNull ComponentName service, @NonNull String pollingLoopFilter, boolean autoTransact)474 public boolean registerPollingLoopFilterForService(@NonNull ComponentName service, 475 @NonNull String pollingLoopFilter, boolean autoTransact) { 476 final String pollingLoopFilterV = validatePollingLoopFilter(pollingLoopFilter); 477 return callServiceReturn(() -> 478 sService.registerPollingLoopFilterForService( 479 mContext.getUser().getIdentifier(), service, pollingLoopFilterV, autoTransact), 480 false); 481 } 482 483 /** 484 * Unregister a polling loop filter (PLF) for a HostApduService. If the PLF had previously been 485 * registered via {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)} 486 * for this service it will be removed. 487 * @param service The HostApduService to unregister the filter for 488 * @param pollingLoopFilter The filter to unregister 489 * @return true if the filter was removed, false otherwise 490 * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte 491 */ removePollingLoopFilterForService(@onNull ComponentName service, @NonNull String pollingLoopFilter)492 public boolean removePollingLoopFilterForService(@NonNull ComponentName service, 493 @NonNull String pollingLoopFilter) { 494 final String pollingLoopFilterV = validatePollingLoopFilter(pollingLoopFilter); 495 return callServiceReturn(() -> 496 sService.removePollingLoopFilterForService( 497 mContext.getUser().getIdentifier(), service, pollingLoopFilterV), false); 498 } 499 500 501 /** 502 * Register a polling loop pattern filter (PLPF) for a HostApduService and indicate whether it 503 * should auto-transact or not. The pattern may include the characters 0-9 and A-F as well as 504 * the regular expression operators `.`, `?` and `*` after the first byte. When the beginning of 505 * a non-standard 506 * polling loop frame matches this sequence exactly, it may be delivered to 507 * {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to true and this 508 * service is currently preferred or there are no other services registered for this filter 509 * then observe mode will also be disabled. 510 * 511 * @param service The HostApduService to register the filter for 512 * @param pollingLoopPatternFilter The pattern filter to register, must to be compatible with 513 * {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers 514 * and `.`, `?` and `*` operators 515 * @param autoTransact true to have the NFC stack automatically disable observe mode and allow 516 * transactions to proceed when this filter matches, false otherwise 517 * @return true if the filter was registered, false otherwise 518 * @throws IllegalArgumentException if the filter contains elements other than hexadecimal 519 * numbers and `.`, `?` and `*` operators 520 * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid 521 */ registerPollingLoopPatternFilterForService(@onNull ComponentName service, @NonNull String pollingLoopPatternFilter, boolean autoTransact)522 public boolean registerPollingLoopPatternFilterForService(@NonNull ComponentName service, 523 @NonNull String pollingLoopPatternFilter, boolean autoTransact) { 524 final String pollingLoopPatternFilterV = 525 validatePollingLoopPatternFilter(pollingLoopPatternFilter); 526 return callServiceReturn(() -> 527 sService.registerPollingLoopPatternFilterForService( 528 mContext.getUser().getIdentifier(), service, pollingLoopPatternFilterV, 529 autoTransact), 530 false); 531 } 532 533 /** 534 * Unregister a polling loop pattern filter (PLPF) for a HostApduService. If the PLF had 535 * previously been registered via 536 * {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)} for this 537 * service it will be removed. 538 * @param service The HostApduService to unregister the filter for 539 * @param pollingLoopPatternFilter The filter to unregister, must to be compatible with 540 * {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers 541 * and`.`, `?` and `*` operators 542 * @return true if the filter was removed, false otherwise 543 * @throws IllegalArgumentException if the filter containst elements other than hexadecimal 544 * numbers and `.`, `?` and `*` operators 545 * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid 546 */ removePollingLoopPatternFilterForService(@onNull ComponentName service, @NonNull String pollingLoopPatternFilter)547 public boolean removePollingLoopPatternFilterForService(@NonNull ComponentName service, 548 @NonNull String pollingLoopPatternFilter) { 549 final String pollingLoopPatternFilterV = 550 validatePollingLoopPatternFilter(pollingLoopPatternFilter); 551 return callServiceReturn(() -> 552 sService.removePollingLoopPatternFilterForService( 553 mContext.getUser().getIdentifier(), service, pollingLoopPatternFilterV), false); 554 } 555 556 /** 557 * Registers a list of AIDs for a specific category for the 558 * specified service. 559 * 560 * <p>If a list of AIDs for that category was previously 561 * registered for this service (either statically 562 * through the manifest, or dynamically by using this API), 563 * that list of AIDs will be replaced with this one. 564 * 565 * <p>Note that you can only register AIDs for a service that 566 * is running under the same UID as the caller of this API. Typically 567 * this means you need to call this from the same 568 * package as the service itself, though UIDs can also 569 * be shared between packages using shared UIDs. 570 * 571 * @param service The component name of the service 572 * @param category The category of AIDs to be registered 573 * @param aids A list containing the AIDs to be registered 574 * @return whether the registration was successful. 575 */ registerAidsForService(ComponentName service, String category, List<String> aids)576 public boolean registerAidsForService(ComponentName service, String category, 577 List<String> aids) { 578 final AidGroup aidGroup = new AidGroup(aids, category); 579 return callServiceReturn(() -> 580 sService.registerAidGroupForService( 581 mContext.getUser().getIdentifier(), service, aidGroup), false); 582 } 583 584 /** 585 * Unsets the off-host Secure Element for the given service. 586 * 587 * <p>Note that this will only remove Secure Element that was dynamically 588 * set using the {@link #setOffHostForService(ComponentName, String)} 589 * and resets it to a value that was statically assigned using manifest. 590 * 591 * <p>Note that you can only unset off-host SE for a service that 592 * is running under the same UID as the caller of this API. Typically 593 * this means you need to call this from the same 594 * package as the service itself, though UIDs can also 595 * be shared between packages using shared UIDs. 596 * 597 * @param service The component name of the service 598 * @return whether the registration was successful. 599 */ 600 @RequiresPermission(android.Manifest.permission.NFC) 601 @NonNull unsetOffHostForService(@onNull ComponentName service)602 public boolean unsetOffHostForService(@NonNull ComponentName service) { 603 return callServiceReturn(() -> 604 sService.unsetOffHostForService( 605 mContext.getUser().getIdentifier(), service), false); 606 } 607 608 /** 609 * Sets the off-host Secure Element for the given service. 610 * 611 * <p>If off-host SE was initially set (either statically 612 * through the manifest, or dynamically by using this API), 613 * it will be replaced with this one. All AIDs registered by 614 * this service will be re-routed to this Secure Element if 615 * successful. AIDs that was statically assigned using manifest 616 * will re-route to off-host SE that stated in manifest after NFC 617 * toggle. 618 * 619 * <p>Note that you can only set off-host SE for a service that 620 * is running under the same UID as the caller of this API. Typically 621 * this means you need to call this from the same 622 * package as the service itself, though UIDs can also 623 * be shared between packages using shared UIDs. 624 * 625 * <p>Registeration will be successful only if the Secure Element 626 * exists on the device. 627 * 628 * @param service The component name of the service 629 * @param offHostSecureElement Secure Element to register the AID to. Only accept strings with 630 * prefix SIM or prefix eSE. 631 * Ref: GSMA TS.26 - NFC Handset Requirements 632 * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be 633 * SIM[smartcard slot] 634 * (e.g. SIM/SIM1, SIM2… SIMn). 635 * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be 636 * eSE[number] 637 * (e.g. eSE/eSE1, eSE2, etc.). 638 * @return whether the registration was successful. 639 */ 640 @RequiresPermission(android.Manifest.permission.NFC) 641 @NonNull setOffHostForService(@onNull ComponentName service, @NonNull String offHostSecureElement)642 public boolean setOffHostForService(@NonNull ComponentName service, 643 @NonNull String offHostSecureElement) { 644 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); 645 if (adapter == null || offHostSecureElement == null) { 646 return false; 647 } 648 649 List<String> validSE = adapter.getSupportedOffHostSecureElements(); 650 if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE")) 651 || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) { 652 return false; 653 } 654 655 if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")) { 656 return false; 657 } 658 659 if (offHostSecureElement.equals("eSE")) { 660 offHostSecureElement = "eSE1"; 661 } else if (offHostSecureElement.equals("SIM")) { 662 offHostSecureElement = "SIM1"; 663 } 664 final String offHostSecureElementV = new String(offHostSecureElement); 665 return callServiceReturn(() -> 666 sService.setOffHostForService( 667 mContext.getUser().getIdentifier(), service, offHostSecureElementV), false); 668 } 669 670 /** 671 * Retrieves the currently registered AIDs for the specified 672 * category for a service. 673 * 674 * <p>Note that this will only return AIDs that were dynamically 675 * registered using {@link #registerAidsForService(ComponentName, String, List)} 676 * method. It will *not* return AIDs that were statically registered 677 * in the manifest. 678 * 679 * @param service The component name of the service 680 * @param category The category for which the AIDs were registered, 681 * e.g. {@link #CATEGORY_PAYMENT} 682 * @return The list of AIDs registered for this category, or null if it couldn't be found. 683 */ getAidsForService(ComponentName service, String category)684 public List<String> getAidsForService(ComponentName service, String category) { 685 AidGroup group = callServiceReturn(() -> 686 sService.getAidGroupForService( 687 mContext.getUser().getIdentifier(), service, category), null); 688 return (group != null ? group.getAids() : null); 689 } 690 691 /** 692 * Removes a previously registered list of AIDs for the specified category for the 693 * service provided. 694 * 695 * <p>Note that this will only remove AIDs that were dynamically 696 * registered using the {@link #registerAidsForService(ComponentName, String, List)} 697 * method. It will *not* remove AIDs that were statically registered in 698 * the manifest. If dynamically registered AIDs are removed using 699 * this method, and a statically registered AID group for the same category 700 * exists in the manifest, the static AID group will become active again. 701 * 702 * @param service The component name of the service 703 * @param category The category of the AIDs to be removed, e.g. {@link #CATEGORY_PAYMENT} 704 * @return whether the group was successfully removed. 705 */ removeAidsForService(ComponentName service, String category)706 public boolean removeAidsForService(ComponentName service, String category) { 707 return callServiceReturn(() -> 708 sService.removeAidGroupForService( 709 mContext.getUser().getIdentifier(), service, category), false); 710 } 711 712 /** 713 * Allows a foreground application to specify which card emulation service 714 * should be preferred while a specific Activity is in the foreground. 715 * 716 * <p>The specified Activity must currently be in resumed state. A good 717 * paradigm is to call this method in your {@link Activity#onResume}, and to call 718 * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}. 719 * 720 * <p>This method call will fail in two specific scenarios: 721 * <ul> 722 * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT} 723 * category, but the user has indicated that foreground apps are not allowed 724 * to override the default payment service. 725 * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER} 726 * category that are also handled by the default payment service, and the 727 * user has indicated that foreground apps are not allowed to override the 728 * default payment service. 729 * </ul> 730 * 731 * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine 732 * whether foreground apps can override the default payment service. 733 * 734 * <p>Note that this preference is not persisted by the OS, and hence must be 735 * called every time the Activity is resumed. 736 * 737 * @param activity The activity which prefers this service to be invoked 738 * @param service The service to be preferred while this activity is in the foreground 739 * @return whether the registration was successful 740 */ setPreferredService(Activity activity, ComponentName service)741 public boolean setPreferredService(Activity activity, ComponentName service) { 742 // Verify the activity is in the foreground before calling into NfcService 743 if (activity == null || service == null) { 744 throw new NullPointerException("activity or service or category is null"); 745 } 746 return callServiceReturn(() -> sService.setPreferredService(service), false); 747 } 748 749 /** 750 * Unsets the preferred service for the specified Activity. 751 * 752 * <p>Note that the specified Activity must still be in resumed 753 * state at the time of this call. A good place to call this method 754 * is in your {@link Activity#onPause} implementation. 755 * 756 * @param activity The activity which the service was registered for 757 * @return true when successful 758 */ unsetPreferredService(Activity activity)759 public boolean unsetPreferredService(Activity activity) { 760 if (activity == null) { 761 throw new NullPointerException("activity is null"); 762 } 763 return callServiceReturn(() -> sService.unsetPreferredService(), false); 764 } 765 766 /** 767 * Some devices may allow an application to register all 768 * AIDs that starts with a certain prefix, e.g. 769 * "A000000004*" to register all MasterCard AIDs. 770 * 771 * Use this method to determine whether this device 772 * supports registering AID prefixes. 773 * 774 * @return whether AID prefix registering is supported on this device. 775 */ supportsAidPrefixRegistration()776 public boolean supportsAidPrefixRegistration() { 777 return callServiceReturn(() -> sService.supportsAidPrefixRegistration(), false); 778 } 779 780 /** 781 * Retrieves the registered AIDs for the preferred payment service. 782 * 783 * @return The list of AIDs registered for this category, or null if it couldn't be found. 784 */ 785 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 786 @Nullable getAidsForPreferredPaymentService()787 public List<String> getAidsForPreferredPaymentService() { 788 ApduServiceInfo serviceInfo = callServiceReturn(() -> 789 sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null); 790 return (serviceInfo != null ? serviceInfo.getAids() : null); 791 } 792 793 /** 794 * Retrieves the route destination for the preferred payment service. 795 * 796 * <p class="note"> 797 * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service 798 * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This 799 * will return the route for one of the services registered by the role holder (if any). If 800 * there are multiple services registered, it is unspecified which of those will be used to 801 * determine the route. 802 * 803 * @return The route destination secure element name of the preferred payment service. 804 * HCE payment: "Host" 805 * OffHost payment: 1. String with prefix SIM or prefix eSE string. 806 * Ref: GSMA TS.26 - NFC Handset Requirements 807 * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be 808 * SIM[smartcard slot] 809 * (e.g. SIM/SIM1, SIM2… SIMn). 810 * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be 811 * eSE[number] 812 * (e.g. eSE/eSE1, eSE2, etc.). 813 * 2. "OffHost" if the payment service does not specify secure element 814 * name. 815 */ 816 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 817 @Nullable getRouteDestinationForPreferredPaymentService()818 public String getRouteDestinationForPreferredPaymentService() { 819 ApduServiceInfo serviceInfo = callServiceReturn(() -> 820 sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null); 821 if (serviceInfo != null) { 822 if (!serviceInfo.isOnHost()) { 823 return serviceInfo.getOffHostSecureElement() == null ? 824 "OffHost" : serviceInfo.getOffHostSecureElement(); 825 } 826 return "Host"; 827 } 828 return null; 829 } 830 831 /** 832 * Returns a user-visible description of the preferred payment service. 833 * 834 * <p class="note"> 835 * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service 836 * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This 837 * will return the description for one of the services registered by the role holder (if any). 838 * If there are multiple services registered, it is unspecified which of those will be used 839 * to obtain the service description here. 840 * 841 * @return the preferred payment service description 842 */ 843 @RequiresPermission(Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 844 @Nullable getDescriptionForPreferredPaymentService()845 public CharSequence getDescriptionForPreferredPaymentService() { 846 ApduServiceInfo serviceInfo = callServiceReturn(() -> 847 sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null); 848 return (serviceInfo != null ? serviceInfo.getDescription() : null); 849 } 850 851 /** 852 * @hide 853 */ setDefaultServiceForCategory(ComponentName service, String category)854 public boolean setDefaultServiceForCategory(ComponentName service, String category) { 855 return callServiceReturn(() -> 856 sService.setDefaultServiceForCategory( 857 mContext.getUser().getIdentifier(), service, category), false); 858 } 859 860 /** 861 * @hide 862 */ setDefaultForNextTap(ComponentName service)863 public boolean setDefaultForNextTap(ComponentName service) { 864 return callServiceReturn(() -> 865 sService.setDefaultForNextTap( 866 mContext.getUser().getIdentifier(), service), false); 867 } 868 869 /** 870 * @hide 871 */ setDefaultForNextTap(int userId, ComponentName service)872 public boolean setDefaultForNextTap(int userId, ComponentName service) { 873 return callServiceReturn(() -> 874 sService.setDefaultForNextTap(userId, service), false); 875 } 876 877 /** 878 * @hide 879 */ getServices(String category)880 public List<ApduServiceInfo> getServices(String category) { 881 return callServiceReturn(() -> 882 sService.getServices( 883 mContext.getUser().getIdentifier(), category), null); 884 } 885 886 /** 887 * Retrieves list of services registered of the provided category for the provided user. 888 * 889 * @param category Category string, one of {@link #CATEGORY_PAYMENT} or {@link #CATEGORY_OTHER} 890 * @param userId the user handle of the user whose information is being requested. 891 * @hide 892 */ 893 @SystemApi 894 @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) 895 @NonNull getServices(@onNull String category, @UserIdInt int userId)896 public List<ApduServiceInfo> getServices(@NonNull String category, @UserIdInt int userId) { 897 return callServiceReturn(() -> 898 sService.getServices(userId, category), null); 899 } 900 901 /** 902 * Tests the validity of the polling loop filter. 903 * @param pollingLoopFilter The polling loop filter to test. 904 * 905 * @hide 906 */ validatePollingLoopFilter(@onNull String pollingLoopFilter)907 public static @NonNull String validatePollingLoopFilter(@NonNull String pollingLoopFilter) { 908 // Verify hex characters 909 byte[] plfBytes = HexFormat.of().parseHex(pollingLoopFilter); 910 if (plfBytes.length == 0) { 911 throw new IllegalArgumentException( 912 "Polling loop filter must contain at least one byte."); 913 } 914 return HexFormat.of().withUpperCase().formatHex(plfBytes); 915 } 916 917 /** 918 * Tests the validity of the polling loop pattern filter. 919 * @param pollingLoopPatternFilter The polling loop filter to test. 920 * 921 * @hide 922 */ validatePollingLoopPatternFilter( @onNull String pollingLoopPatternFilter)923 public static @NonNull String validatePollingLoopPatternFilter( 924 @NonNull String pollingLoopPatternFilter) { 925 // Verify hex characters 926 if (!PLPF_PATTERN.matcher(pollingLoopPatternFilter).matches()) { 927 throw new IllegalArgumentException( 928 "Polling loop pattern filters may only contain hexadecimal numbers, ?s and *s"); 929 } 930 return Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT)).toString(); 931 } 932 933 /** 934 * A valid AID according to ISO/IEC 7816-4: 935 * <ul> 936 * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars) 937 * <li>Consist of only hex characters 938 * <li>Additionally, we allow an asterisk at the end, to indicate 939 * a prefix 940 * <li>Additinally we allow an (#) at symbol at the end, to indicate 941 * a subset 942 * </ul> 943 * 944 * @hide 945 */ isValidAid(String aid)946 public static boolean isValidAid(String aid) { 947 if (aid == null) 948 return false; 949 950 // If a prefix/subset AID, the total length must be odd (even # of AID chars + '*') 951 if ((aid.endsWith("*") || aid.endsWith("#")) && ((aid.length() % 2) == 0)) { 952 Log.e(TAG, "AID " + aid + " is not a valid AID."); 953 return false; 954 } 955 956 // If not a prefix/subset AID, the total length must be even (even # of AID chars) 957 if ((!(aid.endsWith("*") || aid.endsWith("#"))) && ((aid.length() % 2) != 0)) { 958 Log.e(TAG, "AID " + aid + " is not a valid AID."); 959 return false; 960 } 961 962 // Verify hex characters 963 if (!AID_PATTERN.matcher(aid).matches()) { 964 Log.e(TAG, "AID " + aid + " is not a valid AID."); 965 return false; 966 } 967 968 return true; 969 } 970 971 /** 972 * Allows to set or unset preferred service (category other) to avoid AID Collision. The user 973 * should use corresponding context using {@link Context#createContextAsUser(UserHandle, int)} 974 * 975 * @param service The ComponentName of the service 976 * @param status true to enable, false to disable 977 * @return status code defined in {@link SetServiceEnabledStatusCode} 978 * 979 * @hide 980 */ 981 @SystemApi 982 @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) 983 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 984 @SetServiceEnabledStatusCode setServiceEnabledForCategoryOther(@onNull ComponentName service, boolean status)985 public int setServiceEnabledForCategoryOther(@NonNull ComponentName service, 986 boolean status) { 987 return setServiceEnabledForCategoryOther( 988 service, mContext.getUser().getIdentifier(), status); 989 } 990 991 /** 992 * Same as {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} for a particular 993 * user. 994 * 995 * @param service The ComponentName of the service 996 * @param userId User id 997 * @param status true to enable, false to disable 998 * @return status code defined in {@link SetServiceEnabledStatusCode} 999 * @hide 1000 */ 1001 @SetServiceEnabledStatusCode setServiceEnabledForCategoryOther(@onNull ComponentName service, @UserIdInt int userId, boolean status)1002 public int setServiceEnabledForCategoryOther(@NonNull ComponentName service, 1003 @UserIdInt int userId, boolean status) { 1004 return callServiceReturn(() -> 1005 sService.setServiceEnabledForCategoryOther(userId, 1006 service, status), SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR); 1007 } 1008 1009 /** @hide */ 1010 @IntDef(prefix = "PROTOCOL_AND_TECHNOLOGY_ROUTE_", 1011 value = { 1012 PROTOCOL_AND_TECHNOLOGY_ROUTE_DH, 1013 PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE, 1014 PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC, 1015 PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET, 1016 PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT, 1017 PROTOCOL_AND_TECHNOLOGY_ROUTE_NDEF_NFCEE 1018 }) 1019 @Retention(RetentionPolicy.SOURCE) 1020 public @interface ProtocolAndTechnologyRoute {} 1021 1022 /** 1023 * Setting NFC controller routing table, which includes Protocol Route and Technology Route, 1024 * while this Activity is in the foreground. 1025 * 1026 * The parameter set to {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET} 1027 * can be used to keep current values for that entry. Either 1028 * Protocol Route or Technology Route should be override when calling this API, otherwise 1029 * throw {@link IllegalArgumentException}. 1030 * <p> 1031 * Example usage in an Activity that requires to set proto route to "ESE" and keep tech route: 1032 * <pre> 1033 * protected void onResume() { 1034 * mNfcAdapter.overrideRoutingTable( 1035 * this, {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE}, 1036 * {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET}); 1037 * }</pre> 1038 * </p> 1039 * Also activities must call {@link #recoverRoutingTable(Activity)} 1040 * when it goes to the background. Only the package of the 1041 * currently preferred service (the service set as preferred by the current foreground 1042 * application via {@link CardEmulation#setPreferredService(Activity, ComponentName)} or the 1043 * current Default Wallet Role Holder {@link RoleManager#ROLE_WALLET}), 1044 * otherwise a call to this method will fail and throw {@link SecurityException}. 1045 * @param activity The Activity that requests NFC controller routing table to be changed. 1046 * @param protocol ISO-DEP route destination, where the possible inputs are defined 1047 * in {@link ProtocolAndTechnologyRoute}. 1048 * @param technology Tech-A, Tech-B and Tech-F route destination, where the possible inputs 1049 * are defined in {@link ProtocolAndTechnologyRoute} 1050 * @throws SecurityException if the caller is not the preferred NFC service 1051 * @throws IllegalArgumentException if the activity is not resumed or the caller is not in the 1052 * foreground. 1053 * <p> 1054 * This is a high risk API and only included to support mainline effort 1055 * @hide 1056 */ 1057 @SystemApi 1058 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 1059 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) overrideRoutingTable( @onNull Activity activity, @ProtocolAndTechnologyRoute int protocol, @ProtocolAndTechnologyRoute int technology)1060 public void overrideRoutingTable( 1061 @NonNull Activity activity, @ProtocolAndTechnologyRoute int protocol, 1062 @ProtocolAndTechnologyRoute int technology) { 1063 if (!activity.isResumed()) { 1064 throw new IllegalArgumentException("Activity must be resumed."); 1065 } 1066 String protocolRoute = routeIntToString(protocol); 1067 String technologyRoute = routeIntToString(technology); 1068 callService(() -> 1069 sService.overrideRoutingTable( 1070 mContext.getUser().getIdentifier(), 1071 protocolRoute, 1072 technologyRoute, 1073 mContext.getPackageName())); 1074 } 1075 1076 /** 1077 * Restore the NFC controller routing table, 1078 * which was changed by {@link #overrideRoutingTable(Activity, int, int)} 1079 * 1080 * @param activity The Activity that requested NFC controller routing table to be changed. 1081 * @throws IllegalArgumentException if the caller is not in the foreground. 1082 * 1083 * @hide 1084 */ 1085 @SystemApi 1086 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 1087 @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) recoverRoutingTable(@onNull Activity activity)1088 public void recoverRoutingTable(@NonNull Activity activity) { 1089 if (!activity.isResumed()) { 1090 throw new IllegalArgumentException("Activity must be resumed."); 1091 } 1092 callService(() -> 1093 sService.recoverRoutingTable( 1094 mContext.getUser().getIdentifier())); 1095 } 1096 1097 /** 1098 * Is EUICC supported as a Secure Element EE which supports off host card emulation. 1099 * 1100 * @return true if the device supports EUICC for off host card emulation, false otherwise. 1101 */ 1102 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) isEuiccSupported()1103 public boolean isEuiccSupported() { 1104 return callServiceReturn(() -> sService.isEuiccSupported(), false); 1105 } 1106 1107 /** 1108 * Setting the default subscription ID succeeded. 1109 * @hide 1110 */ 1111 @SystemApi 1112 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) 1113 public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0; 1114 1115 /** 1116 * Setting the default subscription ID failed because the subscription ID is invalid. 1117 * @hide 1118 */ 1119 @SystemApi 1120 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) 1121 public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1; 1122 1123 /** 1124 * Setting the default subscription ID failed because there was an internal error processing 1125 * the request. For ex: NFC service died in the middle of handling the API. 1126 * @hide 1127 */ 1128 @SystemApi 1129 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) 1130 public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2; 1131 1132 /** 1133 * Setting the default subscription ID failed because this feature is not supported on the 1134 * device. 1135 * @hide 1136 */ 1137 @SystemApi 1138 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) 1139 public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3; 1140 1141 /** 1142 * Setting the default subscription ID failed because of unknown error. 1143 * @hide 1144 */ 1145 @SystemApi 1146 @FlaggedApi(Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) 1147 public static final int SET_SUBSCRIPTION_ID_STATUS_UNKNOWN = -1; 1148 1149 /** @hide */ 1150 @IntDef(prefix = "SET_SUBSCRIPTION_ID_STATUS_", 1151 value = { 1152 SET_SUBSCRIPTION_ID_STATUS_SUCCESS, 1153 SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID, 1154 SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR, 1155 SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED, 1156 SET_SUBSCRIPTION_ID_STATUS_UNKNOWN 1157 }) 1158 @Retention(RetentionPolicy.SOURCE) 1159 public @interface SetSubscriptionIdStatus {} 1160 1161 /** 1162 * Sets the system's default NFC subscription id. 1163 * 1164 * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this sets the 1165 * default UICC NFCEE that will handle NFC offhost CE transactions </p> 1166 * 1167 * @param subscriptionId the default NFC subscription Id to set. User can get subscription id 1168 * from {@link SubscriptionManager#getSubscriptionId(int)} 1169 * @return status of the operation. 1170 * 1171 * @throws UnsupportedOperationException If the device does not have 1172 * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. 1173 * @hide 1174 */ 1175 @SystemApi 1176 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) 1177 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 1178 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) setDefaultNfcSubscriptionId(int subscriptionId)1179 public @SetSubscriptionIdStatus int setDefaultNfcSubscriptionId(int subscriptionId) { 1180 return callServiceReturn(() -> 1181 sService.setDefaultNfcSubscriptionId( 1182 subscriptionId, mContext.getPackageName()), 1183 SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR); 1184 } 1185 1186 /** 1187 * Returns the system's default NFC subscription id. 1188 * 1189 * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this returns the 1190 * default UICC NFCEE that will handle NFC offhost CE transactions </p> 1191 * <p> If the device has no UICC that can serve as NFCEE, this will return 1192 * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.</p> 1193 * 1194 * @return the default NFC subscription Id if set, 1195 * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} otherwise. 1196 * 1197 * @throws UnsupportedOperationException If the device does not have 1198 * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. 1199 */ 1200 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) 1201 @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) getDefaultNfcSubscriptionId()1202 public int getDefaultNfcSubscriptionId() { 1203 return callServiceReturn(() -> 1204 sService.getDefaultNfcSubscriptionId(mContext.getPackageName()), 1205 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 1206 } 1207 1208 /** 1209 * Returns the value of {@link Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT}. 1210 * 1211 * @param context A context 1212 * @return A ComponentName for the setting value, or null. 1213 * 1214 * @hide 1215 */ 1216 @SystemApi 1217 @UserHandleAware 1218 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 1219 @SuppressWarnings("AndroidFrameworkClientSidePermissionCheck") 1220 @FlaggedApi(android.permission.flags.Flags.FLAG_WALLET_ROLE_ENABLED) 1221 @Nullable getPreferredPaymentService(@onNull Context context)1222 public static ComponentName getPreferredPaymentService(@NonNull Context context) { 1223 context.checkCallingOrSelfPermission(Manifest.permission.NFC_PREFERRED_PAYMENT_INFO); 1224 String defaultPaymentComponent = Settings.Secure.getString(context.getContentResolver(), 1225 Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT); 1226 1227 if (defaultPaymentComponent == null) { 1228 return null; 1229 } 1230 1231 return ComponentName.unflattenFromString(defaultPaymentComponent); 1232 } 1233 1234 /** @hide */ 1235 interface ServiceCall { call()1236 void call() throws RemoteException; 1237 } 1238 /** @hide */ callService(ServiceCall call)1239 public static void callService(ServiceCall call) { 1240 try { 1241 if (sService == null) { 1242 NfcAdapter.attemptDeadServiceRecovery( 1243 new RemoteException("NFC CardEmulation Service is null")); 1244 sService = NfcAdapter.getCardEmulationService(); 1245 } 1246 call.call(); 1247 } catch (RemoteException e) { 1248 NfcAdapter.attemptDeadServiceRecovery(e); 1249 sService = NfcAdapter.getCardEmulationService(); 1250 try { 1251 call.call(); 1252 } catch (RemoteException ee) { 1253 ee.rethrowAsRuntimeException(); 1254 } 1255 } 1256 } 1257 /** @hide */ 1258 interface ServiceCallReturn<T> { call()1259 T call() throws RemoteException; 1260 } 1261 /** @hide */ callServiceReturn(ServiceCallReturn<T> call, T defaultReturn)1262 public static <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) { 1263 try { 1264 if (sService == null) { 1265 NfcAdapter.attemptDeadServiceRecovery( 1266 new RemoteException("NFC CardEmulation Service is null")); 1267 sService = NfcAdapter.getCardEmulationService(); 1268 } 1269 return call.call(); 1270 } catch (RemoteException e) { 1271 NfcAdapter.attemptDeadServiceRecovery(e); 1272 sService = NfcAdapter.getCardEmulationService(); 1273 // Try one more time 1274 try { 1275 return call.call(); 1276 } catch (RemoteException ee) { 1277 ee.rethrowAsRuntimeException(); 1278 } 1279 } 1280 return defaultReturn; 1281 } 1282 1283 /** @hide */ routeIntToString(@rotocolAndTechnologyRoute int route)1284 public static String routeIntToString(@ProtocolAndTechnologyRoute int route) { 1285 return switch (route) { 1286 case PROTOCOL_AND_TECHNOLOGY_ROUTE_DH -> "DH"; 1287 case PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE -> "eSE"; 1288 case PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC -> "SIM"; 1289 case PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET -> null; 1290 case PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT -> "default"; 1291 case PROTOCOL_AND_TECHNOLOGY_ROUTE_NDEF_NFCEE-> "NDEF-NFCEE"; 1292 default -> throw new IllegalStateException("Unexpected value: " + route); 1293 }; 1294 } 1295 1296 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) 1297 public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0; 1298 1299 /** 1300 * This error is reported when the NFC command watchdog restarts the NFC stack. 1301 */ 1302 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) 1303 public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1; 1304 1305 /** 1306 * This error is reported when the NFC controller does not respond or there's an NCI transport 1307 * error. 1308 */ 1309 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) 1310 public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2; 1311 1312 /** 1313 * This error is reported when the NFC stack times out while waiting for a response to a command 1314 * sent to the NFC hardware. 1315 */ 1316 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) 1317 public static final int NFC_INTERNAL_ERROR_COMMAND_TIMEOUT = 3; 1318 1319 /** @hide */ 1320 @Retention(RetentionPolicy.SOURCE) 1321 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) 1322 @IntDef(prefix = "NFC_INTERNAL_ERROR_", value = { 1323 NFC_INTERNAL_ERROR_UNKNOWN, 1324 NFC_INTERNAL_ERROR_NFC_CRASH_RESTART, 1325 NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR, 1326 NFC_INTERNAL_ERROR_COMMAND_TIMEOUT, 1327 }) 1328 public @interface NfcInternalErrorType {} 1329 1330 /** 1331 * Callback interface for NFC-related events. 1332 * 1333 * These callbacks will be called when registered with 1334 * {@link #registerNfcEventCallback(Executor, NfcEventCallback)} and while the registered caller 1335 * is still alive. When you are done listening to the callbacks, you should unregister it with 1336 * {@link #unregisterNfcEventCallback(NfcEventCallback)}. 1337 */ 1338 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) 1339 public interface NfcEventCallback { 1340 /** 1341 * This method is called when this package gains or loses preferred NFC service status. 1342 * This can happen by way of either it becoming the default wallet role holder 1343 * (see {@link android.app.role.RoleManager#ROLE_WALLET}) or the preferred service of the 1344 * foreground activity, set with {@link #setPreferredService(Activity, ComponentName)}. 1345 * 1346 * @param isPreferred true is this service has become the preferred NFC service, false if it 1347 * is no longer the preferred service 1348 */ 1349 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onPreferredServiceChanged(boolean isPreferred)1350 default void onPreferredServiceChanged(boolean isPreferred) {} 1351 1352 /** 1353 * This method is called when observe mode has been enabled or disabled. 1354 * 1355 * @param isEnabled true if observe mode has been enabled, false if it has been disabled 1356 */ 1357 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onObserveModeStateChanged(boolean isEnabled)1358 default void onObserveModeStateChanged(boolean isEnabled) {} 1359 1360 /** 1361 * This method is called when observe mode has been disabled in the firmware. 1362 * 1363 * @param exitFrame The polling frame that caused the firmware to exit observe mode. Null 1364 * when we were unable to parse the exit frame from the NFCC. 1365 * @hide 1366 */ 1367 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onObserveModeDisabledInFirmware(@ullable PollingFrame exitFrame)1368 default void onObserveModeDisabledInFirmware(@Nullable PollingFrame exitFrame) {} 1369 1370 /** 1371 * This method is called when an AID conflict is detected during an NFC transaction. This 1372 * can happen when multiple services are registered for the same AID. If your service is 1373 * registered for this AID you may want to instruct users to bring your app to the 1374 * foreground and ensure you call {@link #setPreferredService(Activity, ComponentName)} 1375 * to ensure the transaction is routed to your service. 1376 * 1377 * @param aid The AID that is in conflict 1378 */ 1379 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onAidConflictOccurred(@onNull String aid)1380 default void onAidConflictOccurred(@NonNull String aid) {} 1381 1382 /** 1383 * This method is called when an AID is not routed to any service during an NFC 1384 * transaction. This can happen when no service is registered for the given AID. 1385 * 1386 * @param aid the AID that was not routed 1387 */ 1388 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onAidNotRouted(@onNull String aid)1389 default void onAidNotRouted(@NonNull String aid) {} 1390 1391 /** 1392 * This method is called when the NFC adapter state changes. 1393 * 1394 * @param state The new NFC adapter state 1395 */ 1396 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onNfcStateChanged(@fcAdapter.AdapterState int state)1397 default void onNfcStateChanged(@NfcAdapter.AdapterState int state) {} 1398 /** 1399 * This method is called when the NFC controller is in card emulation mode and an NFC 1400 * reader's field is either detected or lost. 1401 * 1402 * @param isDetected true if an NFC reader is detected, false if it is lost 1403 */ 1404 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onRemoteFieldChanged(boolean isDetected)1405 default void onRemoteFieldChanged(boolean isDetected) {} 1406 1407 /** 1408 * This method is called when an internal error is reported by the NFC stack. 1409 * 1410 * No action is required in response to these events as the NFC stack will automatically 1411 * attempt to recover. These errors are reported for informational purposes only. 1412 * 1413 * Note that these errors can be reported when performing various internal NFC operations 1414 * (such as during device shutdown) and cannot always be explicitly correlated with NFC 1415 * transaction failures. 1416 * 1417 * @param errorType The type of the internal error 1418 */ 1419 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) onInternalErrorReported(@fcInternalErrorType int errorType)1420 default void onInternalErrorReported(@NfcInternalErrorType int errorType) {} 1421 } 1422 1423 private final ArrayMap<NfcEventCallback, Executor> mNfcEventCallbacks = new ArrayMap<>(); 1424 1425 final INfcEventCallback mINfcEventCallback = 1426 new INfcEventCallback.Stub() { 1427 public void onPreferredServiceChanged(ComponentNameAndUser componentNameAndUser) { 1428 if (!android.nfc.Flags.nfcEventListener()) { 1429 return; 1430 } 1431 boolean isPreferred = 1432 componentNameAndUser != null 1433 && componentNameAndUser.getUserId() 1434 == mContext.getUser().getIdentifier() 1435 && componentNameAndUser.getComponentName() != null 1436 && Objects.equals( 1437 mContext.getPackageName(), 1438 componentNameAndUser.getComponentName() 1439 .getPackageName()); 1440 callListeners(listener -> listener.onPreferredServiceChanged(isPreferred)); 1441 } 1442 1443 public void onObserveModeStateChanged(boolean isEnabled) { 1444 if (!android.nfc.Flags.nfcEventListener()) { 1445 return; 1446 } 1447 callListeners(listener -> listener.onObserveModeStateChanged(isEnabled)); 1448 } 1449 1450 public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) { 1451 if (!android.nfc.Flags.nfcEventListener()) { 1452 return; 1453 } 1454 callListeners(listener -> listener.onObserveModeDisabledInFirmware(exitFrame)); 1455 } 1456 1457 public void onAidConflictOccurred(String aid) { 1458 if (!android.nfc.Flags.nfcEventListener()) { 1459 return; 1460 } 1461 callListeners(listener -> listener.onAidConflictOccurred(aid)); 1462 } 1463 1464 public void onAidNotRouted(String aid) { 1465 if (!android.nfc.Flags.nfcEventListener()) { 1466 return; 1467 } 1468 callListeners(listener -> listener.onAidNotRouted(aid)); 1469 } 1470 1471 public void onNfcStateChanged(int state) { 1472 if (!android.nfc.Flags.nfcEventListener()) { 1473 return; 1474 } 1475 callListeners(listener -> listener.onNfcStateChanged(state)); 1476 } 1477 1478 public void onRemoteFieldChanged(boolean isDetected) { 1479 if (!android.nfc.Flags.nfcEventListener()) { 1480 return; 1481 } 1482 callListeners(listener -> listener.onRemoteFieldChanged(isDetected)); 1483 } 1484 1485 public void onInternalErrorReported(@NfcInternalErrorType int errorType) { 1486 if (!android.nfc.Flags.nfcEventListener()) { 1487 return; 1488 } 1489 callListeners(listener -> listener.onInternalErrorReported(errorType)); 1490 } 1491 1492 interface ListenerCall { 1493 void invoke(NfcEventCallback listener); 1494 } 1495 1496 private void callListeners(ListenerCall listenerCall) { 1497 synchronized (mNfcEventCallbacks) { 1498 mNfcEventCallbacks.forEach( 1499 (listener, executor) -> { 1500 executor.execute(() -> listenerCall.invoke(listener)); 1501 }); 1502 } 1503 } 1504 }; 1505 linkToNfcDeath()1506 private void linkToNfcDeath() { 1507 try { 1508 mDeathRecipient = new IBinder.DeathRecipient() { 1509 @Override 1510 public void binderDied() { 1511 synchronized (mNfcEventCallbacks) { 1512 mDeathRecipient = null; 1513 sService = null; 1514 } 1515 Handler handler = new Handler(Looper.getMainLooper()); 1516 handler.postDelayed(new Runnable() { 1517 public void run() { 1518 try { 1519 synchronized (mNfcEventCallbacks) { 1520 if (mNfcEventCallbacks.size() > 0) { 1521 callService(() -> 1522 sService.registerNfcEventCallback(mINfcEventCallback)); 1523 } 1524 } 1525 } catch (Throwable t) { 1526 handler.postDelayed(this, 50); 1527 } 1528 } 1529 }, 50); 1530 } 1531 }; 1532 sService.asBinder().linkToDeath(mDeathRecipient, 0); 1533 } catch (RemoteException re) { 1534 Log.e(TAG, "Couldn't link to death"); 1535 } 1536 } 1537 1538 /** 1539 * Register a callback for NFC events. 1540 * 1541 * @param executor The Executor to run the call back with 1542 * @param callback The callback to register 1543 */ 1544 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) registerNfcEventCallback( @onNull @allbackExecutor Executor executor, @NonNull NfcEventCallback callback)1545 public void registerNfcEventCallback( 1546 @NonNull @CallbackExecutor Executor executor, @NonNull NfcEventCallback callback) { 1547 if (!android.nfc.Flags.nfcEventListener()) { 1548 return; 1549 } 1550 synchronized (mNfcEventCallbacks) { 1551 mNfcEventCallbacks.put(callback, executor); 1552 if (mNfcEventCallbacks.size() == 1) { 1553 callService(() -> sService.registerNfcEventCallback(mINfcEventCallback)); 1554 linkToNfcDeath(); 1555 } 1556 } 1557 } 1558 1559 private IBinder.DeathRecipient mDeathRecipient; 1560 1561 /** 1562 * Unregister an NFC event callback that was previously registered with {@link 1563 * #registerNfcEventCallback(Executor, NfcEventCallback)}. 1564 * 1565 * @param callback The previously registered callback to unregister 1566 */ 1567 @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) unregisterNfcEventCallback(@onNull NfcEventCallback callback)1568 public void unregisterNfcEventCallback(@NonNull NfcEventCallback callback) { 1569 if (!android.nfc.Flags.nfcEventListener()) { 1570 return; 1571 } 1572 synchronized (mNfcEventCallbacks) { 1573 mNfcEventCallbacks.remove(callback); 1574 if (mNfcEventCallbacks.size() == 0) { 1575 callService(() -> sService.unregisterNfcEventCallback(mINfcEventCallback)); 1576 if (mDeathRecipient != null) { 1577 sService.asBinder().unlinkToDeath(mDeathRecipient, 0); 1578 mDeathRecipient = null; 1579 } 1580 } 1581 } 1582 } 1583 } 1584