Reputation: 63
I have make an application for read and write on NFC TAG. But, while I am scanning Empty NFC Tag after opening my application it not responding as I expected as my Application Toast Message "Tag is empty". But, when I close my application then I receiving Mobile belting message.
Basically, I need the help as following:
I am including my code here.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mylab.myapplication">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication">
<activity
android:name=".MainActivity"
android:exported="true">
<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.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Write a message: ">
</TextView>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20sp" >
<EditText
android:id="@+id/edit_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:hint="message" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Write" />
</LinearLayout>
<TextView
android:id="@+id/nfc_contents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
nfc_tech_filter.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.Ndef</tech>
<!-- class name -->
</tech-list>
</resources>
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String ERROR_DETECTED = "No NFC tag detected!";
public static final String WRITE_SUCCESS = "Text written to the NFC tag successfully!";
public static final String WRITE_ERROR = "Error during writing, is the NFC tag close enough to your device?";
NfcAdapter nfcAdapter;
PendingIntent pendingIntent;
IntentFilter writeTagFilters[];
boolean writeMode;
Tag myTag;
Context context;
TextView tvNFCContent;
TextView message;
Button btnWrite;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
tvNFCContent = (TextView) findViewById(R.id.nfc_contents);
message = (TextView) findViewById(R.id.edit_message);
btnWrite = (Button) findViewById(R.id.button);
btnWrite.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
try {
if(myTag ==null) {
Toast.makeText(context, ERROR_DETECTED, Toast.LENGTH_LONG).show();
} else {
write(message.getText().toString(), myTag);
Toast.makeText(context, WRITE_SUCCESS, Toast.LENGTH_LONG ).show();
}
} catch (IOException e) {
Toast.makeText(context, WRITE_ERROR, Toast.LENGTH_LONG ).show();
e.printStackTrace();
} catch (FormatException e) {
Toast.makeText(context, WRITE_ERROR, Toast.LENGTH_LONG ).show();
e.printStackTrace();
}
}
});
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
// Stop here, we definitely need NFC
Toast.makeText(this, "This device doesn't support NFC.", Toast.LENGTH_LONG).show();
finish();
}
readFromIntent(getIntent());
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
writeTagFilters = new IntentFilter[] { tagDetected };
}
/******************************************************************************
**********************************Read From NFC Tag***************************
******************************************************************************/
private void readFromIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs = null;
if (rawMsgs != null) {
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
}
}
buildTagViews(msgs);
}
}
private void buildTagViews(NdefMessage[] msgs) {
if (msgs == null || msgs.length == 0) return;
String text = "";
// String tagId = new String(msgs[0].getRecords()[0].getType());
byte[] payload = msgs[0].getRecords()[0].getPayload();
String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; // Get the Text Encoding
int languageCodeLength = payload[0] & 0063; // Get the Language Code, e.g. "en"
// String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
try {
// Get the Text
text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
} catch (UnsupportedEncodingException e) {
Log.e("UnsupportedEncoding", e.toString());
}
tvNFCContent.setText("NFC Content: " + text);
}
/******************************************************************************
**********************************Write to NFC Tag****************************
******************************************************************************/
private void write(String text, Tag tag) throws IOException, FormatException {
NdefRecord[] records = { createRecord(text) };
NdefMessage message = new NdefMessage(records);
// Get an instance of Ndef for the tag.
Ndef ndef = Ndef.get(tag);
// Enable I/O
ndef.connect();
// Write the message
ndef.writeNdefMessage(message);
// Close the connection
ndef.close();
}
private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
String lang = "en";
byte[] textBytes = text.getBytes();
byte[] langBytes = lang.getBytes("US-ASCII");
int langLength = langBytes.length;
int textLength = textBytes.length;
byte[] payload = new byte[1 + langLength + textLength];
// set status byte (see NDEF spec for actual bits)
payload[0] = (byte) langLength;
// copy langbytes and textbytes into payload
System.arraycopy(langBytes, 0, payload, 1, langLength);
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
NdefRecord recordNFC = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
return recordNFC;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
readFromIntent(intent);
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
}
}
@Override
public void onPause(){
super.onPause();
WriteModeOff();
}
@Override
public void onResume(){
super.onResume();
WriteModeOn();
}
/******************************************************************************
**********************************Enable Write********************************
******************************************************************************/
private void WriteModeOn(){
writeMode = true;
nfcAdapter.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null);
}
/******************************************************************************
**********************************Disable Write*******************************
******************************************************************************/
private void WriteModeOff(){
writeMode = false;
nfcAdapter.disableForegroundDispatch(this);
}
}
Upvotes: 0
Views: 1611
Reputation: 10152
To handle unformatted Ndef Tags change your "nfc_tech_filter.xml" file to the one below:-
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.Ndef</tech>
<tech>android.nfc.tech.NdefFormatable</tech>
</tech-list>
</resources>
This way your app says it want's to be notified when a NdefFormatable
tag is detected, this will stop you seeing the Android OS displaying it's own message when one of these tags is presented. (The OS will still show a message if a Tag that is never capable of storing an Ndef message is presented)
Then refactor handling the intent passed by the system to your app to handle tag passed
private void readFromIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs = null;
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
}
buildTagViews(msgs);
}
}
private void write(String text, Tag tag) throws IOException, FormatException {
NdefRecord[] records = { createRecord(text) };
NdefMessage message = new NdefMessage(records);
// Get an instance of Ndef for the tag.
Ndef ndef = Ndef.get(tag);
// If Ndef.get is null then try formatting it and adding message
if (ndef != null) {
// Enable I/O
ndef.connect();
// Write the message
ndef.writeNdefMessage(message);
// Close the connection
ndef.close();
} else {
NdefFormatable ndefFormatable = NdefFormatable.get(tag);
// Really should do a null test on ndefFormatable here but as the code is looking for an exception don't test for null
ndefFormatable.connect();
// Format at write message at the same time
ndefFormatable.format(NdefMessage);
ndefFormatable.close();
}
}
Hopefully this should work, I don't use the old enableForegroundDispatch
API any more as it was too unreliable when trying to write to Tags, enableReaderMode
is much better.
Note I cleaned up the readFromIntent
method there is no point in trying to read an Ndef message from a Tag that does not have one as ACTION_NDEF_DISCOVERED is always enumerated before the other Actions if the Tag has an Ndef message on it.
Also note that I've not fixed fact that writeNdefMessage
and format
as per the docs
It must not be called from the main application thread
Really it is a lot better to enableReaderMode API for NFC (Unless you need NFC support below Android API level 19) as Tags with this automatically are handled on a separate thread.
Upvotes: 2