Android Question different behaviors in NFC library connect

rbirago

Active Member
Licensed User
Longtime User
In the past weeks I have hardly studied how to dialog with Credit Cards using APDUs. To manage all the different cards (EMV standard) I have to use NFC library to connect the card and then start to get APDU commands/responses to read the credit card data (ie. card number).
I have noticed that in the whole connection of the nfc card there are different behaviors:
Trying to connect a standard Visa card the connection is a breeze. See the log:
B4X:
Logger connesso a:  Telpo M1K
--------- beginning of main
** Service (starter) Destroy (ignored)**
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create (first time) **
** Activity (main) Resume **
action:android.intent.action.MAIN
** Activity (main) Pause, UserClosed = false **
Killing previous instance (main).
** Activity (main) Create  **
** Activity (main) Resume **
action:android.nfc.action.TECH_DISCOVERED
Techs: [android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
getId:086C7AA4
Connected: true
Then I tried to connect an Amex card and a Mastercard debit card. This is the log:
B4X:
Logger connesso a:  Telpo M1K
--------- beginning of main
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create (first time) **
** Activity (main) Resume **
action:android.intent.action.MAIN
** Activity (main) Pause, UserClosed = false **
Killing previous instance (main).
** Activity (main) Create  **
** Activity (main) Resume **
action:android.nfc.action.TECH_DISCOVERED
Techs: [android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
getId:04871D5A631090
Connected: true
** Activity (main) Pause, UserClosed = true **
As you can notice after the correct connection the app goes in PAUSE UserClosed=true.
This bahavior causes (if the card is close to the device) a indefinite loop of Connections.
Also using Mastercard debit it works in this strange way.
Any suggestion?
Attached the simple app I used to test these behaviors.
 

rbirago

Active Member
Licensed User
Longtime User
ooops! I noticed that the zipped app is not attached as too large (576Kb). How can I attach this test app?
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
if I cannot attach the zip at least I can copy the source:
B4X:
#Region  Project Attributes
    #ApplicationLabel: TestConnect
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private xui As XUI
    Private prevIntent As Intent
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    Private nfc As NFC
    Private TagTech As TagTechnology
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
End Sub

Sub Activity_Resume
    Dim si As Intent = Activity.GetStartingIntent
    'check that the intent is a new intent
    If si.IsInitialized = False Or si = prevIntent Then Return
    prevIntent = si
    Log("action:" & si.Action)
    If si.Action.EndsWith("TECH_DISCOVERED") Or si.Action.EndsWith("NDEF_DISCOVERED") Or si.Action.EndsWith("TAG_DISCOVERED") Then
        Dim techs As List = nfc.GetTechList(si)
        Log($"Techs: ${techs}"$)
        If techs.IndexOf("android.nfc.tech.NfcA") > -1 Then
            TagTech.Initialize("TagTech", "android.nfc.tech.NfcA" , si)
            Dim jo As JavaObject = TagTech
            Dim tag As JavaObject = jo.RunMethod("getTag", Null)
            Dim rawId() As Byte = tag.RunMethod("getId", Null)
            Dim bc As ByteConverter
            Log("getId:" & bc.HexFromBytes(rawId)) 'bc = ByteConverter
'            Connect To the tag
            TagTech.Connect
          Else
            Log("Tag does not support NfcA")
        End If
    End If
End Sub

Private Sub TagTech_Connected (Success As Boolean)
    Log($"Connected: ${Success}"$)
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello world!", "B4X")
End Sub
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
If someone wants to test the app I remember that you have to implement Manifest:
XML:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: https://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
CreateResourceFromFile(Macro, Themes.LightTheme)
'End of default text.
AddPermission(android.permission.NFC)

AddActivityText(Main, <intent-filter>

                <action android:name="android.nfc.action.TECH_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter"/>)
and to add the nfc_tech_filter.xml under objects/res/xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">

    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
</resources>
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
if you want someone to look at a project that is too large to post
on the forum, you upload it to your (free) google drive space and
post the link to it. interested parties can then download it.

it's too easy to draw mistaken conclusions from the snippet and
log entries that you show. for example, it's not clear what happens
between lines 15 and 16 in the second log series. you would need
to study the unfiltered log. also, it's not clear from your code snippet
whether or not you close the connection. and, of course, it may be
difficult to duplicate what you experience without your device and the
cards you were trying to read in the way you were trying to read them.

you might want to try this project to see if you can duplicate the problem:
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
Thanks for the quick reply. I try to answer to your questions.
First of all I have performed the same test on a debit card using unfiltered log. This is the log:
B4X:
Logger connesso a:  Telpo M1K
--------- beginning of main
Using CollectorTypeCC GC.
Not starting debugger since process cannot load the jdwp agent.
Binder ioctl to enable oneway spam detection failed: Invalid argument
Compat change id reported: 171979766; UID 10155; state: ENABLED
Configuring clns-4 for other apk /data/app/~~t5W241ocbLFEjHq8xu4nPA==/b4a.example-21iPaNRIXyxhVAbZoHisAQ==/base.apk. target_sdk_version=33, uses_libraries=, library_path=/data/app/~~t5W241ocbLFEjHq8xu4nPA==/b4a.example-21iPaNRIXyxhVAbZoHisAQ==/lib/arm64, permitted_path=/data:/mnt/expand:/data/user/0/b4a.example
ANGLE Developer option for 'b4a.example' set to: 'default'
Neither updatable production driver nor prerelease driver is supported.
No Network Security Config specified, using platform default
No Network Security Config specified, using platform default
common created.
Starting remote logger. Port: 35352
[static] sSurfaceFactory = com.mediatek.view.impl.SurfaceFactoryImpl@6b0fe20
[static] sMsyncFactory = com.mediatek.view.impl.MsyncFactoryImpl@38a23d9
--------- beginning of system
loadTunerAppList +
loadTunerAppList -
hardware acceleration = true, sRendererEnabled = true, forceHwAccelerated = false
PowerHalWrapper.getInstance
[](id:1c3a00000000,api:0,p:-1,c:7226) connect: controlledByApp=false
[ViewRootImpl[main]#0] constructor()
Binder ioctl to enable oneway spam detection failed: Invalid argument
EglManager::makeCurrent mED = 0x1, surface = 0x0, mEC = 0xb400006f5f54cc00, error = EGL_SUCCESS
[ViewRootImpl[main]#0(BLAST Consumer)0](id:1c3a00000000,api:1,p:7226,c:7226) connect: api=1 producerControlledByApp=true
ioctl c0044901 failed with code -1: Invalid argument
fbcNotifyFrameComplete error: undefined symbol: fbcNotifyFrameComplete
fbcNotifyNoRender error: undefined symbol: fbcNotifyNoRender
Compat change id reported: 147798919; UID 10155; state: ENABLED
*** Debugger waiting for connection (0) ***
After accept
*** Debugger waiting for connection (1) ***
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create (first time) **
** Activity (main) Resume **
action:android.intent.action.MAIN
** Activity (main) Pause, UserClosed = false **
Killing previous instance (main).
hardware acceleration = true, sRendererEnabled = true, forceHwAccelerated = false
[](id:1c3a00000001,api:0,p:-1,c:7226) connect: controlledByApp=false
[ViewRootImpl[main]#1] constructor()
[ViewRootImpl[main]#1(BLAST Consumer)1](id:1c3a00000001,api:1,p:7226,c:7226) connect: api=1 producerControlledByApp=true
** Activity (main) Create  **
** Activity (main) Resume **
action:android.nfc.action.TECH_DISCOVERED
Techs: [android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
getId:0585FBFE474300
Connected: true
[ViewRootImpl[main]#0(BLAST Consumer)0](id:1c3a00000000,api:1,p:7226,c:7226) disconnect: api 1
[ViewRootImpl[main]#0] destructor()
[ViewRootImpl[main]#0(BLAST Consumer)0](id:1c3a00000000,api:0,p:-1,c:7226) disconnect
[Warning] assignParent to null: this = DecorView@2661079[main]
releaseBufferCallbackThunk bufferId:31035433680897 framenumber:31 blastBufferQueue is dead
** Activity (main) Pause, UserClosed = true **
ged_boost_gpu_freq, level 100, eOrigin 2, final_idx 2, oppidx_max 2, oppidx_min 0
Cleared Reference was only reachable from finalizer (only reported once)
EglManager::makeCurrent mED = 0x1, surface = 0x0, mEC = 0xb400006f5f54cc00, error = EGL_SUCCESS
[ViewRootImpl[main]#1(BLAST Consumer)1](id:1c3a00000001,api:1,p:7226,c:7226) disconnect: api 1
[ViewRootImpl[main]#1] destructor()
[ViewRootImpl[main]#1(BLAST Consumer)1](id:1c3a00000001,api:0,p:-1,c:7226) disconnect
[Warning] assignParent to null: this = DecorView@85ba96c[main]
releaseBufferCallbackThunk bufferId:31035433680908 framenumber:31 blastBufferQueue is dead
So you can understand (I don't) what happens between "lines 15 and 16".
I can confirm that physically the card is posed on the device and no other actions are done.
I do not close the connection.
The B4aTapCard was my first chance some weeks ago but, as you know, it manages directly the connection and the definition of the commands to use. It was a precious resource to understand what commands are performed and the relative responses well parsed to understand the meaning. It was my main study object.
In that times I understood that if I want to manage different situations of different NFC cards I have to apply directly APDU commands (I think it was a suggestion just by you).
Have you any further suggestions to go ahead?
Thank you
Roberto
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
This is the log with no filter for the connection of a standard VISA card (that is ok):
B4X:
** Activity (main) Pause, UserClosed = true **
ged_boost_gpu_freq, level 100, eOrigin 2, final_idx 2, oppidx_max 2, oppidx_min 0
EglManager::makeCurrent mED = 0x1, surface = 0x0, mEC = 0xb400006f5f54d6b0, error = EGL_SUCCESS
[ViewRootImpl[main]#1(BLAST Consumer)1](id:1f5600000001,api:1,p:8022,c:8022) disconnect: api 1
[ViewRootImpl[main]#1] destructor()
[ViewRootImpl[main]#1(BLAST Consumer)1](id:1f5600000001,api:0,p:-1,c:8022) disconnect
[Warning] assignParent to null: this = DecorView@85ba96c[main]
releaseBufferCallbackThunk bufferId:34454227648529 framenumber:33 blastBufferQueue is dead
hardware acceleration = true, sRendererEnabled = true, forceHwAccelerated = false
[](id:1f5600000002,api:0,p:-1,c:8022) connect: controlledByApp=false
[ViewRootImpl[main]#2] constructor()
[ViewRootImpl[main]#2(BLAST Consumer)2](id:1f5600000002,api:1,p:8022,c:8022) connect: api=1 producerControlledByApp=true
** Activity (main) Create  **
** Activity (main) Resume **
action:android.nfc.action.TECH_DISCOVERED
Techs: [android.nfc.tech.IsoDep, android.nfc.tech.NfcA]
getId:081647C0
Connected: true
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
i'm trying to determine if the problem is you, the device, the cards or the process.

it would be helpful to know if you have installed any credit card reader apps and if you are able to
read the cards you refer to in your post with those apps. even a good general nfc-scanning app would work.
i would like to eliminate the device or the cards as suspects.

i would also suggest you upload your project to google drive for download. if you are using 3rd party
libraries that you have installed in your additional libraries folder, you need to include them as well.
i would ask about your app's flow, but it might be easier simply for me to run the app.

you say you do not close the connection. that is a bad sign already.

i have no unexplainable problems reading different types of nfc tags, but your problem today might be my problem
tomorrow. i am willing to spend some time with this.
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
First of all thanks for your attention to my questions.
Now, I have uploaded B4a project on my GoogleDrive space. This is the link: I Use only standard libraries (NFC, JavaObject, ByteConverter).
All the 3 cards I've used in my trials are well working in normal shops for NFC payments (really Amex gold was working only in a couple of situations).
The first one (Visa Credit) works fine in all situations.
The second one (PagoBancomat + Debit Mastercard) are recognized by B4aTapcard (but after the first two Command/Response steps the app gives an 80 81 response instead of a 77 59 and then it goes in a loop of strange command/responses). Using EMVCardReader by com.gt.alimert.emvcardreader it works fine.
The third one (Amex gold) does not work in any case. EMVCardReader gives the message "CARD ERROR > CALL YOUR BANK".
That's all.
Remember that my original question is: why after the TagTech_Connected event for case 2 & 3 (both with Success=true) the app triggers an Activity_Pause UserClose=true event?

Really I have other steps to face (ie.: how is formed the parameter data field in the command 80 A8) but I think that for now it is better to go on step-by-step.
Thank you
Roberto
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
so, i have to apologize; i misunderstood the topic of your thread.
my interest in nfc tags blinded me somewhat to what appears to
be the real topic: the userclose value when your app enters pause.

i would suggest you start a thread for that topic. although i believe
userclose is supposed to indicate whether the user has tapped the
back or home key or has otherwise instructed the app to finish, this
is something only erel can definitively confirm, and he might have
missed it if he only saw a post referring to nfc. he does have to scan
a lot of posts appearing daily.

i have downloaded and run your project. i am able to duplicate the
userclose=true behavior with working cards.

you need to add:
B4X:
Sub Activity_Resume
    nfc.EnableForegroundDispatch
                  .....
end sub

and:
B4X:
Private Sub TagTech_Connected (Success As Boolean)
    Log($"Connected: ${Success}"$)
    Log("thank you for connecting.  Now closing that connection")
    TagTech.Close
End Sub

when i add the changes, the behavior disappears. try them on your end.
enabling foregrounddispatch is what stops the loop. it has to do with how nfc is
handled by the os. i realize this does not address userclose; hence the need for
a different thread.

judging by your last post, there seem to be issues with at least 1 of your test cards. how a
given application responds is a matter of implementation. each of the major card distributors
embeds different versions of its own distinct operating systems in their cards. the degree to
which behavior across these systems is shared has its limits; data returned by a visa may have
a different meaning with an amex. or no meaning at all. or even an error.

in any case, step by step. see if my changes remove the loop
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
Really I have verified that just one VISA card I've tested works in the matter I was thinking: after connection opening it has no strange actions like pausing UserClose=true. All the others have that strange behavior. Of course if I close TagTech there is no loop (nfc.EnableForegroundDispatch has another function: to inform the system that THIS app is the destination of the NFC read action and nfc.DisableForegroundDispatch is the reset of this duty).
I will ask to the forum further questions about in a different post, but for now I can get a workaround to go to the next step.
For now thanks for the help. Tomorrow I will post a new specific post to my next hard question regarding APDU command configuration to Get Processing Options (GPO).
thank you
Roberto
 
Upvote 0
Top