Skip to content

Instantly share code, notes, and snippets.

@pognon
Last active March 13, 2022 15:16
Show Gist options
  • Save pognon/4977423 to your computer and use it in GitHub Desktop.
Save pognon/4977423 to your computer and use it in GitHub Desktop.
NFC Demo
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.ippon.mobile.nfcdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="15" />
<uses-feature
android:name="android.hardware.nfc"
android:required="false" />
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".NFCInventoryActivity"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
public class NFCInventoryActivity extends Activity{
private static final String TAG = "nfcinventory_simple";
// NFC-related variables
NfcAdapter mNfcAdapter;
PendingIntent mNfcPendingIntent;
IntentFilter[] mReadTagFilters;
/* Called when the activity will start interacting with the user. */
@Override
protected void onResume(){
// ....
// Handle foreground NFC scanning in this activity by creating a
// PendingIntent with FLAG_ACTIVITY_SINGLE_TOP flag so each new scan
// is not added to the Back Stack
mNfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// Create intent filter to handle NDEF NFC tags detected from inside our
// application when in "read mode":
IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try{
ndefDetected.addDataType("application/fr.ippon.nfcdemo");
} catch (MalformedMimeTypeException e){
throw new RuntimeException("Could not add MIME type.", e);
}
// create IntentFilter arrays:
mReadTagFilters = new IntentFilter[] { ndefDetected };
// Enable priority for current activity to detect scanned tags
mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent, mReadTagFilters, null);
}
/* Called when the system is about to start resuming a previous activity. */
@Override
protected void onPause()
{
// ...
mNfcAdapter.disableForegroundDispatch(this);
// ...
}
}
public class NFCInventoryActivity extends Activity {
// ......
/* Called when the activity will start interacting with the user. */
@Override
protected void onResume() {
// .....
if (getIntent().getAction() != null) {
// tag received when app is not running and not in the foreground:
if (getIntent().getAction().equals(
NfcAdapter.ACTION_NDEF_DISCOVERED)) {
NdefMessage[] msgs = getNdefMessagesFromIntent(getIntent());
// Do something with the NDEF message here...
}
}
// .....
}
/*
* This is called for activities that set launchMode to "singleTop" or
* "singleTask" in their manifest package, or if a client used the
* FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent).
*/
@Override
protected void onNewIntent(Intent intent) {
// .....
if (intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
NdefMessage[] msgs = getNdefMessagesFromIntent(intent);
// Do something with the NDEF message here
} else if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
Toast.makeText(this,
"This NFC tag currently has no inventory NDEF data.",
Toast.LENGTH_LONG).show();
}
// ....
}
// ......
}
public class NFCInventoryActivity extends Activity implements CreateNdefMessageCallback
{
private static final String TAG = "nfcinventory_simple";
// NFC-related variables
NfcAdapter mNfcAdapter;
PendingIntent mNfcPendingIntent;
IntentFilter[] mReadTagFilters;
IntentFilter[] mWriteTagFilters;
private boolean mWriteMode = false;
// UI elements
EditText mName;
EditText mRAM;
EditText mProcessor;
AlertDialog mWriteTagDialog;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// set the main.xml layout of 3 editable textfields and an update
// button:
setContentView(R.layout.nfc);
findViewById(R.id.write_tag).setOnClickListener(mTagWriter);
findViewById(R.id.share).setOnClickListener(mTagWriter);
mName = ((EditText) findViewById(R.id.computer_name));
mRAM = ((EditText) findViewById(R.id.computer_ram));
mProcessor = ((EditText) findViewById(R.id.computer_processor));
// add change listeners to the text field so the available peer-to-peer
// data is kept up to date
mName.addTextChangedListener(mTextWatcher);
mRAM.addTextChangedListener(mTextWatcher);
mProcessor.addTextChangedListener(mTextWatcher);
// get an instance of the context's cached NfcAdapter
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
// register the callback
// usage: setNdefPushMessageCallback( callback, activity, optionalExtraActivities)
mNfcAdapter.setNdefPushMessageCallback(this,this);
// if null is returned this demo cannot run. Use this check if the
// "required" parameter of <uses-feature> in the manifest is not set
if (mNfcAdapter == null)
{
Toast.makeText(this,
"Your device does not support NFC. Cannot run demo.",
Toast.LENGTH_LONG).show();
finish();
return;
}
// check if NFC is enabled
checkNfcEnabled();
// Handle foreground NFC scanning in this activity by creating a
// PendingIntent with FLAG_ACTIVITY_SINGLE_TOP flag so each new scan
// is not added to the Back Stack
mNfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// Create intent filter to handle NDEF NFC tags detected from inside our
// application when in "read mode":
IntentFilter ndefDetected = new IntentFilter(
NfcAdapter.ACTION_NDEF_DISCOVERED);
try
{
ndefDetected.addDataType("app/fr.nfcdemo"); //app/fr.ippon.nfcdemo
} catch (MalformedMimeTypeException e)
{
throw new RuntimeException("Could not add MIME type.", e);
}
// Create intent filter to detect any NFC tag when attempting to write
// to a tag in "write mode"
IntentFilter tagDetected = new IntentFilter(
NfcAdapter.ACTION_TAG_DISCOVERED);
// create IntentFilter arrays:
mWriteTagFilters = new IntentFilter[] { tagDetected };
mReadTagFilters = new IntentFilter[] { ndefDetected, tagDetected };
}
/* Called when the activity will start interacting with the user. */
@Override
protected void onResume()
{
super.onResume();
// Double check if NFC is enabled
checkNfcEnabled();
Log.d(TAG, "onResume: " + getIntent());
if (getIntent().getAction() != null)
{
// tag received when app is not running and not in the foreground:
if (getIntent().getAction().equals(
NfcAdapter.ACTION_NDEF_DISCOVERED))
{
NdefMessage[] msgs = getNdefMessagesFromIntent(getIntent());
NdefRecord record = msgs[0].getRecords()[0];
byte[] payload = record.getPayload();
setTextFieldValues(new String(payload));
}
}
// Enable priority for current activity to detect scanned tags
// enableForegroundDispatch( activity, pendingIntent,
// intentsFiltersArray, techListsArray );
mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent,
mReadTagFilters, null);
// Enable peer-to-peer push of NDEF data
//mNfcAdapter.enableForegroundNdefPush( this, createNdefFromJson());
mNfcAdapter.setNdefPushMessage(createNdefFromJson(), this);
}
/* Called when the system is about to start resuming a previous activity. */
@Override
protected void onPause()
{
super.onPause();
Log.d(TAG, "onPause: " + getIntent());
mNfcAdapter.disableForegroundDispatch(this);
//mNfcAdapter.disableForegroundNdefPush(this);
mNfcAdapter.setNdefPushMessage(null, this);
}
/*
* This is called for activities that set launchMode to "singleTop" or
* "singleTask" in their manifest package, or if a client used the
* FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent).
*/
@Override
protected void onNewIntent(Intent intent)
{
Log.d(TAG, "onNewIntent: " + intent);
if (!mWriteMode)
{
// Currently in tag READING mode
if (intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
{
NdefMessage[] msgs = getNdefMessagesFromIntent(intent);
confirmDisplayedContentOverwrite(msgs[0]);
} else if (intent.getAction().equals(
NfcAdapter.ACTION_TAG_DISCOVERED))
{
Toast.makeText(this,
"This NFC tag currently has no inventory NDEF data.",
Toast.LENGTH_LONG).show();
}
} else
{
// Currently in tag WRITING mode
if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED))
{
Tag detectedTag = intent
.getParcelableExtra(NfcAdapter.EXTRA_TAG);
writeTag(createNdefFromJson(), detectedTag);
mWriteTagDialog.cancel();
}
}
}
/*
* **** READING MODE METHODS ****
*/
NdefMessage[] getNdefMessagesFromIntent(Intent intent)
{
// Parse the intent
NdefMessage[] msgs = null;
String action = intent.getAction();
if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)
|| action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
{
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.");
finish();
}
return msgs;
}
private void confirmDisplayedContentOverwrite(final NdefMessage msg)
{
new AlertDialog.Builder(this)
.setTitle(getString(R.string.new_tag_found))
.setMessage(getString(R.string.replace_current_tag))
.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int id)
{
// use the current values in the NDEF payload
// to update the text fields
String payload = new String(msg.getRecords()[0]
.getPayload());
setTextFieldValues(payload);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int id)
{
dialog.cancel();
}
}).show();
}
private void setTextFieldValues(String jsonString)
{
JSONObject inventory = null;
String name = "";
String ram = "";
String processor = "";
try
{
inventory = new JSONObject(jsonString);
name = inventory.getString("n"); // name
ram = inventory.getString("r"); // ram
processor = inventory.getString("p"); // processor
} catch (JSONException e)
{
Log.e(TAG, "Couldn't parse JSON: ", e);
}
Editable nameField = mName.getText();
nameField.clear();
nameField.append(name);
Editable ramField = mRAM.getText();
ramField.clear();
ramField.append(ram);
Editable processorField = mProcessor.getText();
processorField.clear();
processorField.append(processor);
}
private TextWatcher mTextWatcher = new TextWatcher()
{
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3)
{
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3)
{
}
@Override
public void afterTextChanged(Editable arg0)
{
// if (mResumed)
// {
//mNfcAdapter.enableForegroundNdefPush(NFCInventoryActivity.this, createNdefFromJson());
mNfcAdapter.setNdefPushMessage(createNdefFromJson(), NFCInventoryActivity.this);
// }
}
};
/*
* **** WRITING MODE METHODS ****
*/
private View.OnClickListener mTagWriter = new View.OnClickListener()
{
@Override
public void onClick(View arg0)
{
switch (arg0.getId()) {
case R.id.write_tag:
enableTagWriteMode();
AlertDialog.Builder builder = new AlertDialog.Builder(
NFCInventoryActivity.this)
.setTitle(getString(R.string.ready_to_write))
.setMessage(getString(R.string.ready_to_write_instructions))
.setCancelable(true)
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog,
int id)
{
dialog.cancel();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener()
{
@Override
public void onCancel(DialogInterface dialog)
{
enableTagReadMode();
}
});
mWriteTagDialog = builder.create();
mWriteTagDialog.show();
break;
case R.id.share:
// do soemthing
break;
default:
break;
}
}
};
private NdefMessage createNdefFromJson()
{
// get the values from the form's text fields:
Editable nameField = mName.getText();
Editable ramField = mRAM.getText();
Editable processorField = mProcessor.getText();
// create a JSON object out of the values:
JSONObject computerSpecs = new JSONObject();
try
{
computerSpecs.put("n", nameField); // name
computerSpecs.put("r", ramField); // ram
computerSpecs.put("p", processorField); // processor
} catch (JSONException e)
{
Log.e(TAG, "Could not create JSON: ", e);
}
// create a new NDEF record and containing NDEF message using the app's
// custom MIME type:
String mimeType = "app/fr.nfcdemo"; // application/fr.ippon.nfcdemo
byte[] mimeBytes = mimeType.getBytes(Charset.forName("UTF-8"));
String data = computerSpecs.toString();
byte[] dataBytes = data.getBytes(Charset.forName("UTF-8"));
byte[] id = new byte[0];
NdefRecord record = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,
mimeBytes, id, dataBytes);
NdefMessage m = new NdefMessage(new NdefRecord[] { record });
// return the NDEF message
return m;
}
private void enableTagWriteMode()
{
mWriteMode = true;
mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent,
mWriteTagFilters, null);
}
private void enableTagReadMode()
{
mWriteMode = false;
mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent,
mReadTagFilters, null);
}
boolean writeTag(NdefMessage message, Tag tag)
{
int size = message.toByteArray().length;
try
{
Ndef ndef = Ndef.get(tag);
if (ndef != null)
{
ndef.connect();
if (!ndef.isWritable())
{
Toast.makeText(this,
"Cannot write to this tag. This tag is read-only.",
Toast.LENGTH_LONG).show();
return false;
}
if (ndef.getMaxSize() < size)
{
Toast.makeText(
this,
"Cannot write to this tag. Message size (" + size
+ " bytes) exceeds this tag's capacity of "
+ ndef.getMaxSize() + " bytes.",
Toast.LENGTH_LONG).show();
return false;
}
ndef.writeNdefMessage(message);
Toast.makeText(this,
"A pre-formatted tag was successfully updated.",
Toast.LENGTH_LONG).show();
return true;
} else
{
NdefFormatable format = NdefFormatable.get(tag);
if (format != null)
{
try
{
format.connect();
format.format(message);
Toast.makeText(
this,
"This tag was successfully formatted and updated.",
Toast.LENGTH_LONG).show();
return true;
} catch (IOException e)
{
Toast.makeText(
this,
"Cannot write to this tag due to I/O Exception.",
Toast.LENGTH_LONG).show();
return false;
}
} else
{
Toast.makeText(
this,
"Cannot write to this tag. This tag does not support NDEF.",
Toast.LENGTH_LONG).show();
return false;
}
}
} catch (Exception e)
{
Toast.makeText(this,
"Cannot write to this tag due to an Exception.",
Toast.LENGTH_LONG).show();
}
return false;
}
/*
* **** HELPER METHODS ****
*/
private void checkNfcEnabled()
{
Boolean nfcEnabled = mNfcAdapter.isEnabled();
if (!nfcEnabled)
{
new AlertDialog.Builder(NFCInventoryActivity.this)
.setTitle(getString(R.string.warning_nfc_is_off))
.setMessage(getString(R.string.turn_on_nfc))
.setCancelable(false)
.setPositiveButton("Update Settings",
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog,
int id)
{
startActivity(new Intent(
android.provider.Settings.ACTION_WIRELESS_SETTINGS));
}
}).create().show();
}
}
@Override
public NdefMessage createNdefMessage(NfcEvent arg0) {
NdefMessage msg = createNdefFromJson();
return msg;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment