Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: launch app with NFC when in background #2

Merged
merged 9 commits into from
Jul 30, 2024
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "phonegap-nfc",
"version": "1.2.0",
"version": "1.2.1",
"description": "Near Field Communication (NFC) Plugin. Read and write NDEF messages to NFC tags and share NDEF messages with peers.",
"cordova": {
"id": "phonegap-nfc",
Expand Down Expand Up @@ -33,4 +33,4 @@
"url": "https://github.com/chariotsolutions/phonegap-nfc/issues"
},
"homepage": "https://github.com/chariotsolutions/phonegap-nfc#readme"
}
}
88 changes: 58 additions & 30 deletions src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

Expand Down Expand Up @@ -33,6 +34,7 @@
import android.nfc.tech.TagTechnology;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.util.Log;

Expand All @@ -50,7 +52,6 @@ public class NfcPlugin extends CordovaPlugin {
private static final String ENABLED = "enabled";
private static final String INIT = "init";
private static final String SHOW_SETTINGS = "showSettings";
private static final String PARSE_LAUNCH_INTENT = "parseLaunchIntent";

private static final String NDEF = "ndef";
private static final String NDEF_MIME = "ndef-mime";
Expand Down Expand Up @@ -85,10 +86,27 @@ public class NfcPlugin extends CordovaPlugin {
private CallbackContext readerModeCallback;
private CallbackContext channelCallback;

private PostponedPluginResult postponedPluginResult = null;

class PostponedPluginResult {
private Date moment;
private PluginResult pluginResult;

PostponedPluginResult(Date moment, PluginResult pluginResult) {
this.moment = moment;
this.pluginResult = pluginResult;
}

boolean isValid() {
return this.moment.after(new Date(new Date().getTime() - 30000));
}
}

@Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {

Log.d(TAG, "execute " + action);
// Log.d(TAG, "execute postponedPluginResult.toString() " + postponedPluginResult.toString());

// showSettings can be called if NFC is disabled
// might want to skip this if NO_NFC
Expand All @@ -98,8 +116,24 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo
}

// the channel is set up when the plugin starts
if (action.equalsIgnoreCase(CHANNEL)) {
// if (action.equalsIgnoreCase(CHANNEL)) {
if (action.equalsIgnoreCase(READER_MODE)) {
channelCallback = callbackContext;

if (postponedPluginResult != null) {
Log.i(TAG, "Postponed plugin result available");

if (postponedPluginResult.isValid()) {
Log.i(TAG, "Postponed plugin result is valid, resending it now");

channelCallback.sendPluginResult(postponedPluginResult.pluginResult);
} else {
Log.i(TAG, "Postponed plugin result not valid anymore, so ignoring it");
}

postponedPluginResult = null;
}

return true; // short circuit
}

Expand Down Expand Up @@ -152,10 +186,6 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo

} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);

} else if (action.equalsIgnoreCase(PARSE_LAUNCH_INTENT)) {
parseLaunchIntent(callbackContext);

} else if (action.equalsIgnoreCase(ENABLED)) {
// status is checked before every call
// if code made it here, NFC is enabled
Expand Down Expand Up @@ -183,12 +213,6 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo
return true;
}

@Override
protected void pluginInitialize() {
super.pluginInitialize();
NfcActivity.onPluginInitialize();
}

private String getNfcStatus() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter == null) {
Expand Down Expand Up @@ -233,12 +257,11 @@ public void onTagDiscovered(Tag tag) {
Ndef ndef = Ndef.get(tag);
json = Util.ndefToJSON(ndef);
} else {
json = Util.tagToJSON(tag);
json = Util.tagToJSON(tag, null);
}

Intent tagIntent = new Intent();
tagIntent.putExtra(NfcAdapter.EXTRA_TAG, tag);
savedIntent = tagIntent;
setIntent(tagIntent);

PluginResult result = new PluginResult(PluginResult.Status.OK, json);
Expand Down Expand Up @@ -319,10 +342,10 @@ private void parseLaunchIntent(final CallbackContext callbackContext) {
if (ndef != null) {
callbackContext.success(buildNdefJSON(ndef, messages));
} else {
callbackContext.success(Util.tagToJSON(tag));
callbackContext.success(Util.tagToJSON(tag, messages));
}
} else if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
callbackContext.success(Util.tagToJSON(tag));
callbackContext.success(Util.tagToJSON(tag, messages));
} else {
if (data != null) {
callbackContext.success(data);
Expand Down Expand Up @@ -368,7 +391,7 @@ private void registerMimeType(JSONArray data, CallbackContext callbackContext) t
private void eraseTag(CallbackContext callbackContext) {
Tag tag = savedIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NdefRecord[] records = {
new NdefRecord(NdefRecord.TNF_EMPTY, new byte[0], new byte[0], new byte[0])
new NdefRecord(NdefRecord.TNF_EMPTY, new byte[0], new byte[0], new byte[0])
};
writeNdefMessage(new NdefMessage(records), tag, callbackContext);
}
Expand All @@ -394,7 +417,7 @@ private void writeNdefMessage(final NdefMessage message, final Tag tag, final Ca
int size = message.toByteArray().length;
if (ndef.getMaxSize() < size) {
callbackContext.error("Tag capacity is " + ndef.getMaxSize() +
" bytes, message is " + size + " bytes.");
" bytes, message is " + size + " bytes.");
} else {
ndef.writeNdefMessage(message);
callbackContext.success();
Expand Down Expand Up @@ -661,7 +684,7 @@ private void parseMessage() {
}

if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
fireTagEvent(tag);
fireTagEvent(tag, messages);
}

setIntent(new Intent());
Expand All @@ -673,12 +696,17 @@ private void sendEvent(String type, JSONObject tag) {

try {
JSONObject event = new JSONObject();
event.put("type", type); // TAG_DEFAULT, NDEF, NDEF_MIME, NDEF_FORMATABLE
event.put("tag", tag); // JSON representing the NFC tag and NDEF messages
event.put("type", type); // TAG_DEFAULT, NDEF, NDEF_MIME, NDEF_FORMATABLE
event.put("tag", tag); // JSON representing the NFC tag and NDEF messages

PluginResult result = new PluginResult(PluginResult.Status.OK, event);
result.setKeepCallback(true);
channelCallback.sendPluginResult(result);

if (channelCallback != null) {
channelCallback.sendPluginResult(result);
} else {
postponedPluginResult = new PostponedPluginResult(new Date(), result);
}
} catch (JSONException e) {
Log.e(TAG, "Error sending NFC event through the channel", e);
}
Expand All @@ -691,11 +719,11 @@ private void fireNdefEvent(String type, Ndef ndef, Parcelable[] messages) {
}

private void fireNdefFormatableEvent(Tag tag) {
sendEvent(NDEF_FORMATABLE, Util.tagToJSON(tag));
sendEvent(NDEF_FORMATABLE, Util.tagToJSON(tag, null));
}

private void fireTagEvent(Tag tag) {
sendEvent(TAG_DEFAULT, Util.tagToJSON(tag));
private void fireTagEvent(Tag tag, Parcelable[] messages) {
sendEvent(TAG_DEFAULT, Util.tagToJSON(tag, messages));
}

private JSONObject buildNdefJSON(Ndef ndef, Parcelable[] messages) {
Expand Down Expand Up @@ -780,8 +808,8 @@ private void setIntent(Intent intent) {
* Enable I/O operations to the tag from this TagTechnology object.
* *
*
* @param tech TagTechnology class name e.g. 'android.nfc.tech.IsoDep' or 'android.nfc.tech.NfcV'
* @param timeout tag timeout
* @param tech TagTechnology class name e.g. 'android.nfc.tech.IsoDep' or 'android.nfc.tech.NfcV'
* @param timeout tag timeout
* @param callbackContext Cordova callback context
*/
private void connect(final String tech, final int timeout, final CallbackContext callbackContext) {
Expand Down Expand Up @@ -813,9 +841,9 @@ private void connect(final String tech, final int timeout, final CallbackContext
try {
Method maxTransceiveLengthMethod = tagTechnologyClass.getMethod("getMaxTransceiveLength");
resultObject.put("maxTransceiveLength", maxTransceiveLengthMethod.invoke(tagTechnology));
} catch(NoSuchMethodException e) {
} catch (NoSuchMethodException e) {
// Some technologies do not support this, so just ignore.
} catch(JSONException e) {
} catch (JSONException e) {
Log.e(TAG, "Error serializing JSON", e);
}
}
Expand Down Expand Up @@ -895,7 +923,7 @@ private void close(CallbackContext callbackContext) {
/**
* Send raw commands to the tag and receive the response.
*
* @param data byte[] command to be passed to the tag
* @param data byte[] command to be passed to the tag
* @param callbackContext Cordova callback context
*/
private void transceive(final byte[] data, final CallbackContext callbackContext) {
Expand Down
11 changes: 8 additions & 3 deletions src/android/src/com/chariotsolutions/nfc/plugin/Util.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.chariotsolutions.nfc.plugin;

import android.os.Parcelable;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.Tag;
Expand Down Expand Up @@ -38,9 +39,9 @@ static JSONObject ndefToJSON(Ndef ndef) {
// mTag.getTagService(); of the Ndef object sometimes returns null
// see http://issues.mroland.at/index.php?do=details&task_id=47
try {
json.put("canMakeReadOnly", ndef.canMakeReadOnly());
json.put("canMakeReadOnly", ndef.canMakeReadOnly());
} catch (NullPointerException e) {
json.put("canMakeReadOnly", JSONObject.NULL);
json.put("canMakeReadOnly", JSONObject.NULL);
}
} catch (JSONException e) {
Log.e(TAG, "Failed to convert ndef into json: " + ndef.toString(), e);
Expand All @@ -49,13 +50,17 @@ static JSONObject ndefToJSON(Ndef ndef) {
return json;
}

static JSONObject tagToJSON(Tag tag) {
static JSONObject tagToJSON(Tag tag, Parcelable[] messages) {
JSONObject json = new JSONObject();

if (tag != null) {
try {
json.put("id", byteArrayToJSON(tag.getId()));
json.put("techTypes", new JSONArray(Arrays.asList(tag.getTechList())));

if (messages != null && messages.length > 0) {
json.put("ndefMessage", messageToJSON((NdefMessage)messages[0]));
}
} catch (JSONException e) {
Log.e(TAG, "Failed to convert tag into json: " + tag.toString(), e);
}
Expand Down