• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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