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