I need to check if card emulation is enable on a device. I found one method here:
boolean isDefault = CardEmulation
.getInstance(NfcAdapter.getDefaultAdapter(this))
.isDefaultServiceForCategory(
new ComponentName(this, MyPaymentService.class),
CardEmulation.CATEGORY_PAYMENT);
It looks like this works on some devices, but not for all devices.
For example, on the Samsung GT-I9300I (with Android 4.4), there is an NFC module, but it doesn't show the Tap-and-pay options in the settings.
When my app runs on that device I get the following error:
E/CardEmulation: This device does not support card emulation 09-26 16:41:13.592 2625-2625/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.android.settings, PID: 2625 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.settings/com.android.settings.nfc.PaymentDefaultDialog}: java.lang.UnsupportedOperationException at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2441) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2500) at android.app.ActivityThread.access$900(ActivityThread.java:171) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5679) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.UnsupportedOperationException at android.nfc.cardemulation.CardEmulation.getInstance(CardEmulation.java:159) at com.android.settings.nfc.PaymentBackend.(PaymentBackend.java:53) at com.android.settings.nfc.PaymentDefaultDialog.onCreate(PaymentDefaultDialog.java:57) at android.app.Activity.performCreate(Activity.java:5582) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2405) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2500) at android.app.ActivityThread.access$900(ActivityThread.java:171) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5679) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) at dalvik.system.NativeStart.main(Native Method)
However, according to the documentation, CardEmulation
is available since API level 19 (Android 4.4).
So can anyone explain why I'm getting this exception? How can I overcome this problem?
The error is quite clear in the log output:
E/CardEmulation: This device does not support card emulation
This class can only be used on devices that support card emulation and AID-based routing configuration. This is also documented in the documentation of the class CardEmulation
:
Use of this class requires the
FEATURE_NFC_HOST_CARD_EMULATION
to be present on the device.
Consequently, you must only use the method getInstance()
on devices that actually support the HCE feature. Note that host card emulation is a bit misleading here since that feature is also required to manage routing configuration using an OffHostApduService
declaration and to use the CardEmulation
class for any operations related to OffHostApduService
. So this feature applies to both, HCE and management of routing configuration for secure element based card emulation. However, some device manufacturers developed other mechanisms for testing for the availability (and potentailly also for managing the routing) of secure element based card emulation.
You can use the following code to check for the HCE feature before calling the CardEmulation.getInstance()
method:
boolean isDefault = false;
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
isDefault = CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(this))
.isDefaultServiceForCategory(
new ComponentName(this, MyPaymentService.class),
CardEmulation.CATEGORY_PAYMENT);
}