I am working with NFC to read Mifare Classic 1K cards.
The code is working for all Android devices for Android 5.0 and below versions but when I tested my code on devices with Android 5.1, it does not work.
I have tested my code on Nexus 7 (4.4, 5.0), Nexus 5 (5.0), Sony Xperia, and Samsung devices and it was working very fine.
But when Android upgraded from 5.0 to 5.1, in some of the new devices (Nexus 6, Moto x Play) my program does not work.
My code,
MifareClassic mfc = MifareClassic.get(tagFromIntent);
returns null
when I scan my card in Android 5.1 otherwise in versions below 5.1 it works fine.
@SuppressLint("InlinedApi")
public String AuthenticateCard(Context context, Intent nfcIntent) {
String blockData = null;
//Get an instance of the TAG from the NfcAdapter
Tag tagFromIntent = nfcIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String idFromIntent = ByteArrayToHexString(tagFromIntent.getId());
Log.v("onNewIntent()", "NfcAdapter TAG : " + tagFromIntent
+ "NfcAdapter ID : " + idFromIntent);
Log.v("onNewIntent()", "TAG TYPE : " + tagFromIntent.describeContents());
//Get an instance of the Mifare classic card from this TAG intent
//It works successfully with android 5.0 or below versions but returns null in devices with android 5.1.
MifareClassic mfc = MifareClassic.get(tagFromIntent);
try {
// Connect to card
mfc.connect();
// authenticate the sector
if (mfc.authenticateSectorWithKeyA(MY_SECTOR, MY_KEY)) {
for (int k = 0; k < 1; ++k) {
int block = mfc.sectorToBlock(MY_SECTOR) + k;
byte[] data = null;
try {
// Read the block
data = mfc.readBlock(block);
} catch (IOException e) {
Log.e("IOException", "\n" + "Block " + block
+ " data: " + e.getMessage());
continue;
}
// Convert the data into a string from Hex format.
blockData = ByteArrayToHexString(data);
// reading first 8 bytes only
blockData = blockData.substring(0, 8);
}
if (blockData != null) {
mp = MediaPlayer.create(context, R.raw.served);
} else {
mp = MediaPlayer.create(context, R.raw.coins);
}
} else {
Toast.makeText(context, R.string.not_valid_rfid,
Toast.LENGTH_SHORT).show();
mp = MediaPlayer.create(context, R.raw.professionals);
}
mfc.close();
} catch (IOException e) {
mp = MediaPlayer.create(context, R.raw.coins);
Toast.makeText(context, R.string.error_while_scanning,
Toast.LENGTH_SHORT).show();
} catch (NullPointerException e) {
// TODO: handle exception
mp = MediaPlayer.create(context, R.raw.coins);
Toast.makeText(context, R.string.error_while_scanning,
Toast.LENGTH_SHORT).show();
}finally {
try {
if (mfc != null)
mfc.close();
if (mp != null)
mp.start();
} catch (IOException e) {
e.printStackTrace();
}
}
return blockData;
}
The problem that you experience is likely not related to the upgrade to Android 5.1. Instead, obtaining an instance of the MifareClassic
object for a tag will only work on platforms that support MIFARE Classic. Hence,
MifareClassic.get(tagFromIntent)
will return null
on platforms that do not support MIFARE Classic. This essentially means that your app will only work on devices with an NFC chipset from NXP.
Note that there is the system feature com.nxp.mifare
, which should signal if a device supports MIFARE Classic (see ThomasRS's answer) . However, many vendors did not bother to properly configure this. Consequently, using
if (getPackageManager().hasSystemFeature("com.nxp.mifare")) { ... }
is not a very reliable way of identifying devices that support MIFARE Classic.