0

I have realized situation when one android device as an NFC reader communicates with an HCE application installed on another android device. But there were two problems:

  1. It works only when android version of device that acts as an NFC reader is 4.4 and above.
  2. Communication between phones was failing and recovering all the time (reason of deactivation is DEACTIVATION_LINK_LOSS).

Here is the main class of my app for NFC reader:

public class ReadingCardActivity extends Activity {
    // list of NFC technologies detected:
    private final String[][] techList = new String[][]{
            new String[]{
                    NfcA.class.getName(),
                    NfcB.class.getName(),
                    NfcF.class.getName(),
                    NfcV.class.getName(),
                    IsoDep.class.getName(),
                    MifareClassic.class.getName(),
                    MifareUltralight.class.getName(),
                    Ndef.class.getName()
            }
    };
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tag);
        tv = (TextView) findViewById(R.id.tv);
        tv.setMovementMethod(new ScrollingMovementMethod());
    }

    @Override
    protected void onResume() {
        super.onResume();
        // creating pending intent:
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        // creating intent receiver for NFC events:
        IntentFilter filter = new IntentFilter();
        filter.addAction(NfcAdapter.ACTION_TAG_DISCOVERED);
        filter.addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
        filter.addAction(NfcAdapter.ACTION_TECH_DISCOVERED);
        // enabling foreground dispatch for getting intent from NFC event:
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[]{filter}, this.techList);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // disabling foreground dispatch:
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        nfcAdapter.disableForegroundDispatch(this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
            if (intent.getAction() != null) {
                Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                try {
                    IsoDep iso = IsoDep.get(tagFromIntent);
                    iso.connect();
                    tv.setText(tv.getText() + "\nResponse from card: " + Utils.byteArrayToHexString(selectAID(iso)));
                    iso.close();
                } catch (Exception ex) {
                    tv.setText(tv.getText() + "\nException: " + ex.toString());
                }
            }
        }
    }

    public byte[] selectAID(IsoDep iso) throws Exception {
        byte[] wakeUpCommand = {(byte) 0x00, (byte) 0xA4, (byte) 0x04,(byte) 0x00, (byte) 0x08,
                (byte) 0x4C, (byte) 0x65, (byte) 0x6C,(byte) 0x61,
                (byte) 0x6E, (byte) 0x74, (byte) 0x6F, (byte) 0x73,
                (byte) 0x00};
        return iso.transceive(wakeUpCommand);
    }
}

And here is my service in HCE application:

@Override
    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
        sendResult("Terminal sent apdu " + Utils.byteArrayToHexString(apdu));
        byte[] response = Hex.decodeHex(SUCCESSFUL_RESPONSE.toCharArray());
        return response;
}

You might also want to see my apduservice.xml file to see my AID number:

<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
                   android:requireDeviceUnlock="false">
    <aid-group android:category="other">
        <aid-filter android:name="4C656C616E746F73"/>
    </aid-group>
</host-apdu-service>

It's my onDeactivated method in HCE application:

@Override
    public void onDeactivated(int reason) {
        switch (reason) {
            case DEACTIVATION_LINK_LOSS:
                sendResult("\nDeactivation was due to the NFC link being lost.\n");
                break;
            case DEACTIVATION_DESELECTED:
                sendResult("\nDeactivation was due to a different AID being selected.\n");
                break;
        }
    }

And output of HCE application:

+---------------------------------------------+
Terminal sent apdu 00A40400084C656C616E746F7300
Deactivation was due to the NFC link being lost.
Terminal sent apdu 00A40400084C656C616E746F7300
Deactivation was due to the NFC link being lost.
Terminal sent apdu 00A40400084C656C616E746F7300
Deactivation was due to the NFC link being lost.
+---------------------------------------------+

Can anyone help me with these problems?

Ksenia
  • 3,453
  • 7
  • 31
  • 63
  • So what is your actual question? – Michael Roland Jul 07 '15 at 19:18
  • I think I found the answer to my first question, why it works only when android version of device that acts as an NFC reader is 4.4 and above. if I understood correctly, you wrote exactly about this ([link](http://stackoverflow.com/questions/23155719/host-card-emulation-on-android-with-nexus-5/23180223#23180223)): "Thus, the second Android device will not detect your HCE emulated card as an NFC tag. The only way to overcome this limitation is to use the NFC Reader mode API (new in Android 4.4) on the second device". – Ksenia Jul 08 '15 at 09:46
  • So, the second question remains: why was communication between phones failing and recovering all the time? Reason of deactivation is DEACTIVATION_LINK_LOSS. – Ksenia Jul 08 '15 at 09:46
  • So then show us what exactly you are doing on the reader side. – Michael Roland Jul 08 '15 at 12:02
  • I send only one command on the reader side, and this command is `00A40400084C656C616E746F7300` (as described above in method `selectAID`). I added a complete description of the class where the method is (`ReadingCardActivity`). – Ksenia Jul 08 '15 at 14:30
  • By the way, I tried to use the phone with android version 4.4.4 (Sony Xperia Z3 Compact) as a reader, and as a card - a tablet with android version 5.1.3 (Nexus 7), and in this case the permanent disconnection is not observed! P.S. Before, I used the phone Nexus 4 (cyanogenmode 12.1) with android version 5.1.1 as a reader, and the phone Sony Xperia Z3 Compact with android version 4.4.4 as a card. – Ksenia Jul 08 '15 at 14:45
  • It should also be noted that I did not get to use as a reader the tablet with android version 5.1.3 (Nexus 7). Why? Could you explain this? – Ksenia Jul 08 '15 at 14:54
  • It looks like you are establishing a working APDU exchange with the correct AID intent filters set. Good! Is the reader side sending any other APDUs after the initial AID? If not, then could this be just a time-out? – Hauke Sep 16 '15 at 08:14
  • If you found the answer in the meantime, please provide it here. – Hauke Sep 16 '15 at 08:15

0 Answers0