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

Reader mode #326

Merged
merged 7 commits into from
Jun 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ The initial iOS version plugin does not support scanning multiple tags (invalida
- [nfc.beginSession](#nfcbeginsession)
- [nfc.invalidateSession](#nfcinvalidatesession)

## ReaderMode

- [nfc.readerMode](#nfcreadermode)
- [nfc.disableReaderMode](#nfcdisablereadermode)

## Tag Technology Functions

- [nfc.connect](#nfcconnect)
Expand Down Expand Up @@ -584,6 +589,83 @@ Function `invalidateSession` stops the [NFCNDEFReaderSession](https://developer.

- iOS

# Reader Mode Functions

## nfc.readerMode

Read NFC tags sending the tag data to the success callback.

nfc.readerMode(flags, readCallback, errorCallback);

### Description

In reader mode, when a NFC tags is read, the results are returned to read callback as a tag object. Note that the normal event listeners are *not* used in reader mode. The callback receives the tag object *without* the event wrapper.

{
"isWritable": true,
"id": [4, 96, 117, 74, -17, 34, -128],
"techTypes": ["android.nfc.tech.IsoDep", "android.nfc.tech.NfcA", "android.nfc.tech.Ndef"],
"type": "NFC Forum Type 4",
"canMakeReadOnly": false,
"maxSize": 2046,
"ndefMessage": [{
"id": [],
"type": [116, 101, 120, 116, 47, 112, 103],
"payload": [72, 101, 108, 108, 111, 32, 80, 104, 111, 110, 101, 71, 97, 112],
"tnf": 2
}]
}

Foreground dispatching and peer-to-peer functions are disabled when reader mode is enabled.

The flags control which tags are scanned. One benefit to reader mode, is the system sounds can be disabled when a NFC tag is scanned by adding the nfc.FLAG_READER_NO_PLATFORM_SOUNDS flag. See Android's [NfcAdapter.enableReaderMode()](https://developer.android.com/reference/android/nfc/NfcAdapter#enableReaderMode(android.app.Activity,%20android.nfc.NfcAdapter.ReaderCallback,%20int,%20android.os.Bundle)) documentation for more info on the flags.


### Parameters

- __flags__: Flags indicating poll technologies and other optional parameters
- __readCallback__: The callback that is called when a NFC tag is scanned.
- __errorCallback__: The callback that is called when NFC is disabled or missing.

### Quick Example

nfc.readerMode(
nfc.FLAG_READER_NFC_A | nfc.FLAG_READER_NO_PLATFORM_SOUNDS,
nfcTag => console.log(JSON.stringify(nfcTag)),
error => console.log('NFC reader mode failed', error)
);

### Supported Platforms

- Android

## nfc.disableReaderMode

Disable NFC reader mode.

nfc.disableNfcReaderMode(successCallback, errorCallback);

### Description

Disable NFC reader mode.

### Parameters

- __successCallback__: The callback that is called when a NFC reader mode is disabled.
- __errorCallback__: The callback that is called when NFC reader mode can not be disabled.

### Quick Example

nfc.disableReaderMode(
() => console.log('NFC reader mode disabled'),
error => console.log('Error disabling NFC reader mode', error)
)

### Supported Platforms

- Android


# Tag Technology Functions

The tag technology functions provide access to I/O operations on a tag. Connect to a tag, send commands with transceive, close the tag. See the [Android TagTechnology](https://developer.android.com/reference/android/nfc/tech/TagTechnology) and implementations like [IsoDep](https://developer.android.com/reference/android/nfc/tech/IsoDep) and [NfcV](https://developer.android.com/reference/android/nfc/tech/NfcV) for more details. These new APIs are promise based rather than using callbacks.
Expand Down
4 changes: 4 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<uses-feature android:name="android.hardware.nfc" android:required="false"/>
</config-file>

<edit-config file="AndroidManifest.xml" target="/manifest/uses-sdk" mode="merge">
<uses-sdk android:minSdkVersion="19" />
</edit-config>

</platform>

<platform name="wp8">
Expand Down
68 changes: 63 additions & 5 deletions src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.nfc.tech.TagTechnology;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;

Expand Down Expand Up @@ -59,10 +60,8 @@ public class NfcPlugin extends CordovaPlugin implements NfcAdapter.OnNdefPushCom
private static final String NDEF_FORMATABLE = "ndef-formatable";
private static final String TAG_DEFAULT = "tag";

private static final String STATUS_NFC_OK = "NFC_OK";
private static final String STATUS_NO_NFC = "NO_NFC";
private static final String STATUS_NFC_DISABLED = "NFC_DISABLED";
private static final String STATUS_NDEF_PUSH_DISABLED = "NDEF_PUSH_DISABLED";
private static final String READER_MODE = "readerMode";
private static final String DISABLE_READER_MODE = "disableReaderMode";

// TagTechnology IsoDep, NfcA, NfcB, NfcV, NfcF, MifareClassic, MifareUltralight
private static final String CONNECT = "connect";
Expand All @@ -71,6 +70,11 @@ public class NfcPlugin extends CordovaPlugin implements NfcAdapter.OnNdefPushCom
private TagTechnology tagTechnology = null;
private Class<?> tagTechnologyClass;

private static final String STATUS_NFC_OK = "NFC_OK";
private static final String STATUS_NO_NFC = "NO_NFC";
private static final String STATUS_NFC_DISABLED = "NFC_DISABLED";
private static final String STATUS_NDEF_PUSH_DISABLED = "NDEF_PUSH_DISABLED";

private static final String TAG = "NfcPlugin";
private final List<IntentFilter> intentFilters = new ArrayList<>();
private final ArrayList<String[]> techLists = new ArrayList<>();
Expand All @@ -80,6 +84,7 @@ public class NfcPlugin extends CordovaPlugin implements NfcAdapter.OnNdefPushCom

private Intent savedIntent = null;

private CallbackContext readerModeCallback;
private CallbackContext shareTagCallback;
private CallbackContext handoverCallback;

Expand All @@ -95,14 +100,24 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo
return true;
}

// allow reader mode to be disabled even if nfc is disabled
if (action.equalsIgnoreCase(DISABLE_READER_MODE)) {
disableReaderMode(callbackContext);
return true; // short circuit
}

if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}

createPendingIntent();

if (action.equalsIgnoreCase(REGISTER_MIME_TYPE)) {
if (action.equalsIgnoreCase(READER_MODE)) {
int flags = data.getInt(0);
readerMode(flags, callbackContext);

} else if (action.equalsIgnoreCase(REGISTER_MIME_TYPE)) {
registerMimeType(data, callbackContext);

} else if (action.equalsIgnoreCase(REMOVE_MIME_TYPE)) {
Expand Down Expand Up @@ -185,6 +200,49 @@ private String getNfcStatus() {
}
}

private void readerMode(int flags, CallbackContext callbackContext) {
Bundle extras = new Bundle(); // not used
readerModeCallback = callbackContext;
getActivity().runOnUiThread(() -> {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
nfcAdapter.enableReaderMode(getActivity(), callback, flags, extras);
});

}

private void disableReaderMode(CallbackContext callbackContext) {
getActivity().runOnUiThread(() -> {
readerModeCallback = null;
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null) {
nfcAdapter.disableReaderMode(getActivity());
}
callbackContext.success();
});
}

private NfcAdapter.ReaderCallback callback = new NfcAdapter.ReaderCallback() {
@Override
public void onTagDiscovered(Tag tag) {

JSONObject json;

// If the tag supports Ndef, try and return an Ndef message
List<String> techList = Arrays.asList(tag.getTechList());
if (techList.contains(Ndef.class.getName())) {
Ndef ndef = Ndef.get(tag);
json = Util.ndefToJSON(ndef);
} else {
json = Util.tagToJSON(tag);
}

PluginResult result = new PluginResult(PluginResult.Status.OK, json);
result.setKeepCallback(true);
readerModeCallback.sendPluginResult(result);

}
};

private void registerDefaultTag(CallbackContext callbackContext) {
addTagFilter();
callbackContext.success();
Expand Down
20 changes: 19 additions & 1 deletion www/phonegap-nfc.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ var ndef = {

// nfc provides javascript wrappers to the native phonegap implementation
var nfc = {

addTagDiscoveredListener: function (callback, win, fail) {
document.addEventListener("tag", callback, false);
cordova.exec(win, fail, "NfcPlugin", "registerTag", []);
Expand Down Expand Up @@ -527,6 +527,24 @@ var nfc = {

cordova.exec(resolve, reject, 'NfcPlugin', 'transceive', [buffer]);
});
},

// Android NfcAdapter.enableReaderMode flags
FLAG_READER_NFC_A: 0x1,
FLAG_READER_NFC_B: 0x2,
FLAG_READER_NFC_F: 0x4,
FLAG_READER_NFC_V: 0x8,
FLAG_READER_NFC_BARCODE: 0x10,
FLAG_READER_SKIP_NDEF_CHECK: 0x80,
FLAG_READER_NO_PLATFORM_SOUNDS: 0x100,

// Android NfcAdapter.enabledReaderMode
readerMode: function(flags, readCallback, errorCallback) {
cordova.exec(readCallback, errorCallback, 'NfcPlugin', 'readerMode', [flags]);
},

disableReaderMode: function(successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, 'NfcPlugin', 'disableReaderMode', []);
}

};
Expand Down