pinky
pinky

Reputation: 21

NFC read not working

I am newbie in developing android application. Currently I am trying to develop my own tag reader which can read MiFare Ultralight tag.

BUt I failed to read the tag as NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) always return false. Could somebody help me out?

NfcReader.java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mText = (TextView) findViewById(R.id.text);
    mText.setText("Scan a tag");

    mAdapter = NfcAdapter.getDefaultAdapter();

    // Create a generic PendingIntent that will be deliver to this activity. The NFC stack
    // will fill in the intent with the details of the discovered tag before delivering to
    // this activity.
    mPendingIntent = PendingIntent.getActivity(this, 0,
            new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

    // Setup an intent filter for all MIME based dispatches
    IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
    try {
        ndef.addDataType("*/*");
    } catch (MalformedMimeTypeException e) {
        throw new RuntimeException("fail", e);
    }
    mFilters = new IntentFilter[] {
            ndef,
    };

    // Setup a tech list for all NfcF tags
    mTechLists = new String[][] { new String[] { NfcF.class.getName() } };

    Intent intent = getIntent();

    getNdefMessages(intent);
}

public void getNdefMessages(Intent intent) {
    // Parse the intent
    NdefMessage[] msgs = null;
    String action = intent.getAction();
    if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawMsgs != null) {
            msgs = new NdefMessage[rawMsgs.length];
            for (int i = 0; i < rawMsgs.length; i++) {
                msgs[i] = (NdefMessage) rawMsgs[i];
            }
        }
        else {
        // Unknown tag type
            byte[] empty = new byte[] {};
            NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, empty, empty);
            NdefMessage msg = new NdefMessage(new NdefRecord[] {record});
            msgs = new NdefMessage[] {msg};
        }
    }        
    else {
        //Log.e(TAG, "Unknown intent " + intent);
        finish();
    }
}

@Override
public void onResume() {
    super.onResume();
    mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}

@Override
public void onNewIntent(Intent intent) {
    Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
    getNdefMessages(intent);            
}

@Override
public void onPause() {
    super.onPause();
    //mAdapter.disableForegroundDispatch(this);
    throw new RuntimeException("onPause not implemented to fix build");
}

Manifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.nfc.reader"
      android:versionCode="1"
      android:versionName="1.0">

    <uses-permission android:name="android.permission.NFC" />
    <uses-sdk android:minSdkVersion="10"/>
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="NfcReader"
            android:theme="@android:style/Theme.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED"/>
                <data android:mimeType="text/plain" />
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>

            <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfctech" />
        </activity>

    </application>

</manifest> 

Upvotes: 2

Views: 5878

Answers (2)

xilosada
xilosada

Reputation: 320

When a tag with an NDEF message is detected, android looks for any Application with an Activity with intent-filter for action "android.nfc.action.NDEF_DISCOVERED". If two or more applications can handle this action, the one with the most precise filter receives the intent. When applications with the same filter are found, is the user who chooses one. So in your AndroidManifest.xml you have to use this action for detecting NDEF formatted tags.

If you want to read NDEF messages don't worry about which type of tag you are reading (Ultralight, Felica, Topaz,...). Android uses android.nfc.tech.Ndef for dispatch NDEF formatted tags. So for getting all NdefMessages when you activity is on foreground, you can use this snippet:

//Called in onCreate()
private void nfcConfig() {
    mAdapter = NfcAdapter.getDefaultAdapter(this);
    pendingIntent = PendingIntent.getActivity(
            this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    techListsArray = new String[][]{new String[]{
                Ndef.class.getName()
            }};     
}

@Override
public void onResume() {
    super.onResume();
    mAdapter.enableForegroundDispatch(this, pendingIntent, null, techListsArray);
}

@Override
public void onPause() {
    super.onPause();
    mAdapter.disableForegroundDispatch(this);
}

@Override
public void onNewIntent(Intent intent) {
    getNdefMessages(intent);            
}

If you want to read an Ultralight tag ( or another technology), it should be because you need the raw data from the tag. It must not be executed from the main application thread. For example:

private void nfcConfig(){
...
//Mifare Ultralight filter
techListsArray = new String[][]{new String[]{
            NfcA.class.getName(),
            MifareUltralight.class.getName()
        }};
...
}

@Override
public void onNewIntent(Intent intent) {
    getRawData(intent);            
}

private void getRawData(Intent intent){
    final Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    MifareUltralight ulTag = MifareUltralight.getTag();
    new ReadMFULTask(ulTag).execute();
}

private static class ReadMFULTask extends AsyncTask<Void, Void, Void> {

    private Tag mTag;

    public ReadMFULTask(Tag tag){
        mTag = tag;
    }

    @Override
    protected Void doInBackground(Void... arg0) {

    MifareUltralight ulTag = MifareUltralight.get(mTag);
    try {
        ulTag.connect();
            //Read all pages from an Ul tag
            for(int i=0; i < 16; i=i+4){
            byte[] data = ulTag.readPages(i);
                String dataString = HexUtilities.getHexString(data);
                Log.d("RAW DATA", dataString);
            }
            ulTag.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Upvotes: 1

Ben Ward
Ben Ward

Reputation: 884

In your code you are setting your intent filter based on ACTION_TECH_DISCOVERED, but then you try ndef.addDataType(/), which is the way you would go about setting up an intent filter for ACTION_NDEF_DISCOVERED. Instead you could simply do something like this:

IntentFilter ntech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
mFilters = new IntentFilter[]{ ntech };

make sure you have nfc_tech_list.xml set up properly:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
</resources>

Upvotes: 0

Related Questions