Commit c374c44b authored by Leon Han's avatar Leon Han Committed by Commit Bot

[webnfc] Rename NFCWatchOptions to NFCReaderOptions.

This CL just renames NFCWatchOptions to NFCReaderOptions according to
the new spec definition, in preparation for the next step to implement
NFCReader Javascript interface.
http://w3c.github.io/web-nfc/#dom-nfcreaderoptions

The spec change:
https://github.com/w3c/web-nfc/commit/023d6c39f2ccd4dfd1541c259e7810a2b03af762

BUG=520391

Change-Id: I9614c5075c98334a9e573972666c6bd942bd1392
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1638934
Commit-Queue: Leon Han <leon.han@intel.com>
Reviewed-by: default avatarRijubrata Bhaumik <rijubrata.bhaumik@intel.com>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666622}
parent 5b152f15
...@@ -31,7 +31,7 @@ import org.chromium.device.mojom.NfcError; ...@@ -31,7 +31,7 @@ import org.chromium.device.mojom.NfcError;
import org.chromium.device.mojom.NfcErrorType; import org.chromium.device.mojom.NfcErrorType;
import org.chromium.device.mojom.NfcPushOptions; import org.chromium.device.mojom.NfcPushOptions;
import org.chromium.device.mojom.NfcPushTarget; import org.chromium.device.mojom.NfcPushTarget;
import org.chromium.device.mojom.NfcWatchOptions; import org.chromium.device.mojom.NfcReaderOptions;
import org.chromium.mojo.bindings.Callbacks; import org.chromium.mojo.bindings.Callbacks;
import org.chromium.mojo.system.MojoException; import org.chromium.mojo.system.MojoException;
...@@ -103,12 +103,12 @@ public class NfcImpl implements Nfc { ...@@ -103,12 +103,12 @@ public class NfcImpl implements Nfc {
private int mWatcherId; private int mWatcherId;
/** /**
* Map of watchId <-> NfcWatchOptions. All NfcWatchOptions are matched against tag that is in * Map of watchId <-> NfcReaderOptions. All NfcReaderOptions are matched against tag that is in
* proximity, when match algorithm (@see #matchesWatchOptions) returns true, watcher with * proximity, when match algorithm (@see #matchesWatchOptions) returns true, watcher with
* corresponding ID would be notified using NfcClient interface. * corresponding ID would be notified using NfcClient interface.
* @see NfcClient#onWatch(int[] id, NdefMessage message) * @see NfcClient#onWatch(int[] id, NdefMessage message)
*/ */
private final SparseArray<NfcWatchOptions> mWatchers = new SparseArray<>(); private final SparseArray<NfcReaderOptions> mWatchers = new SparseArray<>();
/** /**
* Handler that runs delayed push timeout task. * Handler that runs delayed push timeout task.
...@@ -163,8 +163,8 @@ public class NfcImpl implements Nfc { ...@@ -163,8 +163,8 @@ public class NfcImpl implements Nfc {
/** /**
* Sets NfcClient. NfcClient interface is used to notify mojo NFC service client when NFC * Sets NfcClient. NfcClient interface is used to notify mojo NFC service client when NFC
* device is in proximity and has NdefMessage that matches NfcWatchOptions criteria. * device is in proximity and has NdefMessage that matches NfcReaderOptions criteria.
* @see Nfc#watch(NfcWatchOptions options, WatchResponse callback) * @see Nfc#watch(NfcReaderOptions options, WatchResponse callback)
* *
* @param client @see NfcClient * @param client @see NfcClient
*/ */
...@@ -238,15 +238,15 @@ public class NfcImpl implements Nfc { ...@@ -238,15 +238,15 @@ public class NfcImpl implements Nfc {
/** /**
* Watch method allows to set filtering criteria for NdefMessages that are found when NFC device * Watch method allows to set filtering criteria for NdefMessages that are found when NFC device
* is within proximity. On success, watch ID is returned to caller through WatchResponse * is within proximity. On success, watch ID is returned to caller through WatchResponse
* callback. When NdefMessage that matches NfcWatchOptions is found, it is passed to NfcClient * callback. When NdefMessage that matches NfcReaderOptions is found, it is passed to NfcClient
* interface together with corresponding watch ID. * interface together with corresponding watch ID.
* @see NfcClient#onWatch(int[] id, NdefMessage message) * @see NfcClient#onWatch(int[] id, NdefMessage message)
* *
* @param options used to filter NdefMessages, @see NfcWatchOptions. * @param options used to filter NdefMessages, @see NfcReaderOptions.
* @param callback that is used to notify caller when watch() is completed and return watch ID. * @param callback that is used to notify caller when watch() is completed and return watch ID.
*/ */
@Override @Override
public void watch(NfcWatchOptions options, WatchResponse callback) { public void watch(NfcReaderOptions options, WatchResponse callback) {
if (!checkIfReady(callback)) return; if (!checkIfReady(callback)) return;
int watcherId = ++mWatcherId; int watcherId = ++mWatcherId;
mWatchers.put(watcherId, options); mWatchers.put(watcherId, options);
...@@ -548,7 +548,7 @@ public class NfcImpl implements Nfc { ...@@ -548,7 +548,7 @@ public class NfcImpl implements Nfc {
} }
/** /**
* Iterates through active watchers and if any of those match NfcWatchOptions criteria, * Iterates through active watchers and if any of those match NfcReaderOptions criteria,
* delivers NdefMessage to the client. * delivers NdefMessage to the client.
*/ */
private void notifyMatchingWatchers(android.nfc.NdefMessage message, int compatibility) { private void notifyMatchingWatchers(android.nfc.NdefMessage message, int compatibility) {
...@@ -556,7 +556,7 @@ public class NfcImpl implements Nfc { ...@@ -556,7 +556,7 @@ public class NfcImpl implements Nfc {
NdefMessage ndefMessage = NfcTypeConverter.toNdefMessage(message); NdefMessage ndefMessage = NfcTypeConverter.toNdefMessage(message);
List<Integer> watchIds = new ArrayList<Integer>(); List<Integer> watchIds = new ArrayList<Integer>();
for (int i = 0; i < mWatchers.size(); i++) { for (int i = 0; i < mWatchers.size(); i++) {
NfcWatchOptions options = mWatchers.valueAt(i); NfcReaderOptions options = mWatchers.valueAt(i);
if (matchesWatchOptions(ndefMessage, compatibility, options)) if (matchesWatchOptions(ndefMessage, compatibility, options))
watchIds.add(mWatchers.keyAt(i)); watchIds.add(mWatchers.keyAt(i));
} }
...@@ -577,7 +577,7 @@ public class NfcImpl implements Nfc { ...@@ -577,7 +577,7 @@ public class NfcImpl implements Nfc {
* Implements matching algorithm. * Implements matching algorithm.
*/ */
private boolean matchesWatchOptions( private boolean matchesWatchOptions(
NdefMessage message, int compatibility, NfcWatchOptions options) { NdefMessage message, int compatibility, NfcReaderOptions options) {
// 'nfc-forum' option can only read messages from NFC standard devices and 'vendor' option // 'nfc-forum' option can only read messages from NFC standard devices and 'vendor' option
// can only read from vendor specific ones. // can only read from vendor specific ones.
if (options.compatibility != NdefCompatibility.ANY if (options.compatibility != NdefCompatibility.ANY
......
...@@ -64,7 +64,7 @@ struct NDEFMessage { ...@@ -64,7 +64,7 @@ struct NDEFMessage {
// The |url| field is an ASCII serialized origin, optionally followed by a URL // The |url| field is an ASCII serialized origin, optionally followed by a URL
// path. It represents Web NFC id, that can be used for matching Web NFC // path. It represents Web NFC id, that can be used for matching Web NFC
// content with the filter specified by |url| field in NFCWatchOptions. // content with the filter specified by |url| field in NFCReaderOptions.
string? url; string? url;
// Maximum size of NFC message that can be sent over IPC is 32KB. // Maximum size of NFC message that can be sent over IPC is 32KB.
...@@ -87,7 +87,7 @@ struct NDEFRecordTypeFilter { ...@@ -87,7 +87,7 @@ struct NDEFRecordTypeFilter {
NDEFRecordType record_type; NDEFRecordType record_type;
}; };
struct NFCWatchOptions { struct NFCReaderOptions {
// Defines filtering constraint for NFC messages with specified |url|. // Defines filtering constraint for NFC messages with specified |url|.
string? url; string? url;
...@@ -116,8 +116,8 @@ interface NFC { ...@@ -116,8 +116,8 @@ interface NFC {
CancelPush(NFCPushTarget target) => (NFCError? error); CancelPush(NFCPushTarget target) => (NFCError? error);
// Starts watching for nearby NFC devices with data that matches // Starts watching for nearby NFC devices with data that matches
// NFCWatchOptions filtering criteria. On success, watch id is returned. // NFCReaderOptions filtering criteria. On success, watch id is returned.
Watch(NFCWatchOptions options) => (uint32 id, NFCError? error); Watch(NFCReaderOptions options) => (uint32 id, NFCError? error);
// Cancels watch operation with provided id. // Cancels watch operation with provided id.
CancelWatch (uint32 id) => (NFCError? error); CancelWatch (uint32 id) => (NFCError? error);
......
...@@ -662,7 +662,7 @@ modules_dictionary_idl_files = ...@@ -662,7 +662,7 @@ modules_dictionary_idl_files =
"nfc/ndef_message.idl", "nfc/ndef_message.idl",
"nfc/nfc_push_options.idl", "nfc/nfc_push_options.idl",
"nfc/ndef_record.idl", "nfc/ndef_record.idl",
"nfc/nfc_watch_options.idl", "nfc/nfc_reader_options.idl",
"notifications/get_notification_options.idl", "notifications/get_notification_options.idl",
"notifications/notification_action.idl", "notifications/notification_action.idl",
"notifications/notification_event_init.idl", "notifications/notification_event_init.idl",
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "third_party/blink/renderer/modules/nfc/ndef_message.h" #include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/nfc_error.h" #include "third_party/blink/renderer/modules/nfc/nfc_error.h"
#include "third_party/blink/renderer/modules/nfc/nfc_push_options.h" #include "third_party/blink/renderer/modules/nfc/nfc_push_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_watch_options.h" #include "third_party/blink/renderer/modules/nfc/nfc_reader_options.h"
#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h" #include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
...@@ -48,8 +48,8 @@ using device::mojom::blink::NDEFRecordTypeFilter; ...@@ -48,8 +48,8 @@ using device::mojom::blink::NDEFRecordTypeFilter;
using device::mojom::blink::NFCPushOptions; using device::mojom::blink::NFCPushOptions;
using device::mojom::blink::NFCPushOptionsPtr; using device::mojom::blink::NFCPushOptionsPtr;
using device::mojom::blink::NFCPushTarget; using device::mojom::blink::NFCPushTarget;
using device::mojom::blink::NFCWatchOptions; using device::mojom::blink::NFCReaderOptions;
using device::mojom::blink::NFCWatchOptionsPtr; using device::mojom::blink::NFCReaderOptionsPtr;
NFCPushTarget ToNFCPushTarget(const String& target) { NFCPushTarget ToNFCPushTarget(const String& target) {
if (target == "tag") if (target == "tag")
...@@ -334,13 +334,13 @@ struct TypeConverter<NFCPushOptionsPtr, const blink::NFCPushOptions*> { ...@@ -334,13 +334,13 @@ struct TypeConverter<NFCPushOptionsPtr, const blink::NFCPushOptions*> {
}; };
template <> template <>
struct TypeConverter<NFCWatchOptionsPtr, const blink::NFCWatchOptions*> { struct TypeConverter<NFCReaderOptionsPtr, const blink::NFCReaderOptions*> {
static NFCWatchOptionsPtr Convert( static NFCReaderOptionsPtr Convert(
const blink::NFCWatchOptions* watchOptions) { const blink::NFCReaderOptions* watchOptions) {
// https://w3c.github.io/web-nfc/#the-nfcwatchoptions-dictionary // https://w3c.github.io/web-nfc/#dom-nfcreaderoptions
// Default values for NFCWatchOptions dictionary are: // Default values for NFCReaderOptions dictionary are:
// url = "", recordType = null, mediaType = "", compatibility = "nfc-forum" // url = "", recordType = null, mediaType = "", compatibility = "nfc-forum"
NFCWatchOptionsPtr watchOptionsPtr = NFCWatchOptions::New(); NFCReaderOptionsPtr watchOptionsPtr = NFCReaderOptions::New();
watchOptionsPtr->url = watchOptions->url(); watchOptionsPtr->url = watchOptions->url();
watchOptionsPtr->media_type = watchOptions->mediaType(); watchOptionsPtr->media_type = watchOptions->mediaType();
watchOptionsPtr->compatibility = watchOptionsPtr->compatibility =
...@@ -760,7 +760,7 @@ ScriptPromise NFC::cancelPush(ScriptState* script_state, const String& target) { ...@@ -760,7 +760,7 @@ ScriptPromise NFC::cancelPush(ScriptState* script_state, const String& target) {
// https://w3c.github.io/web-nfc/#dom-nfc-watch // https://w3c.github.io/web-nfc/#dom-nfc-watch
ScriptPromise NFC::watch(ScriptState* script_state, ScriptPromise NFC::watch(ScriptState* script_state,
V8MessageCallback* callback, V8MessageCallback* callback,
const NFCWatchOptions* options) { const NFCReaderOptions* options) {
ScriptPromise promise = RejectIfNotSupported(script_state); ScriptPromise promise = RejectIfNotSupported(script_state);
if (!promise.IsEmpty()) if (!promise.IsEmpty())
return promise; return promise;
...@@ -781,7 +781,7 @@ ScriptPromise NFC::watch(ScriptState* script_state, ...@@ -781,7 +781,7 @@ ScriptPromise NFC::watch(ScriptState* script_state,
WTF::Bind(&NFC::OnWatchRegistered, WrapPersistent(this), WTF::Bind(&NFC::OnWatchRegistered, WrapPersistent(this),
WrapPersistent(ToV8PersistentCallbackFunction(callback)), WrapPersistent(ToV8PersistentCallbackFunction(callback)),
WrapPersistent(resolver)); WrapPersistent(resolver));
nfc_->Watch(device::mojom::blink::NFCWatchOptions::From(options), nfc_->Watch(device::mojom::blink::NFCReaderOptions::From(options),
std::move(watch_callback)); std::move(watch_callback));
return resolver->Promise(); return resolver->Promise();
} }
......
...@@ -20,7 +20,7 @@ namespace blink { ...@@ -20,7 +20,7 @@ namespace blink {
class NFCPushOptions; class NFCPushOptions;
using NDEFMessageSource = StringOrArrayBufferOrNDEFMessage; using NDEFMessageSource = StringOrArrayBufferOrNDEFMessage;
using NDEFRecordData = StringOrUnrestrictedDoubleOrArrayBufferOrDictionary; using NDEFRecordData = StringOrUnrestrictedDoubleOrArrayBufferOrDictionary;
class NFCWatchOptions; class NFCReaderOptions;
class ScriptPromiseResolver; class ScriptPromiseResolver;
class NFC final : public ScriptWrappable, class NFC final : public ScriptWrappable,
...@@ -50,8 +50,10 @@ class NFC final : public ScriptWrappable, ...@@ -50,8 +50,10 @@ class NFC final : public ScriptWrappable,
// Cancels ongoing push operation. // Cancels ongoing push operation.
ScriptPromise cancelPush(ScriptState*, const String&); ScriptPromise cancelPush(ScriptState*, const String&);
// Starts watching for NFC messages that match NFCWatchOptions criteria. // Starts watching for NFC messages that match NFCReaderOptions criteria.
ScriptPromise watch(ScriptState*, V8MessageCallback*, const NFCWatchOptions*); ScriptPromise watch(ScriptState*,
V8MessageCallback*,
const NFCReaderOptions*);
// Cancels watch operation with id. // Cancels watch operation with id.
ScriptPromise cancelWatch(ScriptState*, int32_t id); ScriptPromise cancelWatch(ScriptState*, int32_t id);
......
...@@ -14,7 +14,7 @@ typedef (DOMString or ArrayBuffer or NDEFMessage) NDEFMessageSource; ...@@ -14,7 +14,7 @@ typedef (DOMString or ArrayBuffer or NDEFMessage) NDEFMessageSource;
] interface NFC { ] interface NFC {
[CallWith=ScriptState, MeasureAs=WebNFCPush] Promise<void> push (NDEFMessageSource message, optional NFCPushOptions options); [CallWith=ScriptState, MeasureAs=WebNFCPush] Promise<void> push (NDEFMessageSource message, optional NFCPushOptions options);
[CallWith=ScriptState, MeasureAs=WebNFCCancelPush] Promise<void> cancelPush (optional NFCPushTarget target = "any"); [CallWith=ScriptState, MeasureAs=WebNFCCancelPush] Promise<void> cancelPush (optional NFCPushTarget target = "any");
[CallWith=ScriptState, MeasureAs=WebNFCWatch] Promise<long> watch (MessageCallback callback, optional NFCWatchOptions options); [CallWith=ScriptState, MeasureAs=WebNFCWatch] Promise<long> watch (MessageCallback callback, optional NFCReaderOptions options);
[CallWith=ScriptState, MeasureAs=WebNFCCancelWatch] Promise<void> cancelWatch (optional long id); [CallWith=ScriptState, MeasureAs=WebNFCCancelWatch] Promise<void> cancelWatch (optional long id);
}; };
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
// http://w3c.github.io/web-nfc/#dom-ndefcompatibility // http://w3c.github.io/web-nfc/#dom-ndefcompatibility
enum NDEFCompatibility { "nfc-forum", "vendor", "any" }; enum NDEFCompatibility { "nfc-forum", "vendor", "any" };
// https://w3c.github.io/web-nfc/#the-nfcwatchoptions-dictionary // https://w3c.github.io/web-nfc/#dom-nfcreaderoptions
dictionary NFCWatchOptions { dictionary NFCReaderOptions {
USVString url = ""; USVString url = "";
NDEFRecordType? recordType; NDEFRecordType? recordType;
USVString mediaType = ""; USVString mediaType = "";
......
...@@ -47,7 +47,7 @@ function createNFCPushOptions(target, timeout, ignoreRead) { ...@@ -47,7 +47,7 @@ function createNFCPushOptions(target, timeout, ignoreRead) {
return { target, timeout, ignoreRead }; return { target, timeout, ignoreRead };
} }
function createNFCWatchOptions(url, recordType, mediaType, compatibility) { function createNFCReaderOptions(url, recordType, mediaType, compatibility) {
return { url, recordType, mediaType, compatibility }; return { url, recordType, mediaType, compatibility };
} }
...@@ -222,9 +222,9 @@ function assertNFCPushOptionsEqual(provided, received) { ...@@ -222,9 +222,9 @@ function assertNFCPushOptionsEqual(provided, received) {
assert_equals(received.target, device.mojom.NFCPushTarget.ANY); assert_equals(received.target, device.mojom.NFCPushTarget.ANY);
} }
// Compares NFCWatchOptions structures that were provided to API and // Compares NFCReaderOptions structures that were provided to API and
// received by the mock mojo service. // received by the mock mojo service.
function assertNFCWatchOptionsEqual(provided, received) { function assertNFCReaderOptionsEqual(provided, received) {
if (provided.url !== undefined) if (provided.url !== undefined)
assert_equals(provided.url, received.url); assert_equals(provided.url, received.url);
else else
......
...@@ -24,15 +24,15 @@ nfc_test(() => { ...@@ -24,15 +24,15 @@ nfc_test(() => {
nfc_test(async () => { nfc_test(async () => {
await navigator.nfc.watch(noop); await navigator.nfc.watch(noop);
assertNFCWatchOptionsEqual(createNFCWatchOptions(), mockNFC.watchOptions()); assertNFCReaderOptionsEqual(createNFCReaderOptions(), mockNFC.watchOptions());
}, 'Test that default NFCWatchOptions values are set correctly.') }, 'Test that default NFCReaderOptions values are set correctly.')
nfc_test(async () => { nfc_test(async () => {
let watchOptions = createNFCWatchOptions(test_message_origin, 'json', let watchOptions = createNFCReaderOptions(test_message_origin, 'json',
'application/json', 'any'); 'application/json', 'any');
await navigator.nfc.watch(noop, watchOptions); await navigator.nfc.watch(noop, watchOptions);
assertNFCWatchOptionsEqual(watchOptions, mockNFC.watchOptions()); assertNFCReaderOptionsEqual(watchOptions, mockNFC.watchOptions());
}, 'Test that NFCWatchOptions values are correctly converted.') }, 'Test that NFCReaderOptions values are correctly converted.')
nfc_test(() => { nfc_test(() => {
return assertRejectsWithError(navigator.nfc.cancelWatch(1), 'NotFoundError'); return assertRejectsWithError(navigator.nfc.cancelWatch(1), 'NotFoundError');
...@@ -75,35 +75,35 @@ nfc_test(async () => { ...@@ -75,35 +75,35 @@ nfc_test(async () => {
nfc_test(() => { nfc_test(() => {
return assertRejectsWithError(navigator.nfc.watch(noop, {url:"www.a.com"}), return assertRejectsWithError(navigator.nfc.watch(noop, {url:"www.a.com"}),
'SyntaxError'); 'SyntaxError');
}, 'Test that nfc.watch fails if NFCWatchOptions.url is missing components.'); }, 'Test that nfc.watch fails if NFCReaderOptions.url is missing components.');
nfc_test(() => { nfc_test(() => {
return assertRejectsWithError(navigator.nfc.watch(noop, {url:"invalid"}), return assertRejectsWithError(navigator.nfc.watch(noop, {url:"invalid"}),
'SyntaxError'); 'SyntaxError');
}, 'Test that nfc.watch fails if NFCWatchOptions.url is invalid.'); }, 'Test that nfc.watch fails if NFCReaderOptions.url is invalid.');
nfc_test(() => { nfc_test(() => {
return assertRejectsWithError(navigator.nfc.watch(noop, {url:"http://a.com"}), return assertRejectsWithError(navigator.nfc.watch(noop, {url:"http://a.com"}),
'SyntaxError'); 'SyntaxError');
}, 'Test that nfc.watch fails if NFCWatchOptions.url has wrong protocol.'); }, 'Test that nfc.watch fails if NFCReaderOptions.url has wrong protocol.');
nfc_test(() => { nfc_test(() => {
return navigator.nfc.watch(noop, {url:"https://a.com"}); return navigator.nfc.watch(noop, {url:"https://a.com"});
}, 'Test that nfc.watch succeeds if NFCWatchOptions.url is valid URL.'); }, 'Test that nfc.watch succeeds if NFCReaderOptions.url is valid URL.');
nfc_test(() => { nfc_test(() => {
return navigator.nfc.watch(noop, {url:"https://a.com/*"}); return navigator.nfc.watch(noop, {url:"https://a.com/*"});
}, 'Test that nfc.watch succeeds if NFCWatchOptions.url is valid URL with "*"' + }, 'Test that nfc.watch succeeds if NFCReaderOptions.url is valid URL with "*"' +
' wildcard character in path.'); ' wildcard character in path.');
nfc_test(() => { nfc_test(() => {
return navigator.nfc.watch(noop, {url:"https://foo.com/*/bar"}); return navigator.nfc.watch(noop, {url:"https://foo.com/*/bar"});
}, 'Test that nfc.watch succeeds if NFCWatchOptions.url is valid URL with "*"' + }, 'Test that nfc.watch succeeds if NFCReaderOptions.url is valid URL with "*"' +
' wildcard character in the beginning of path component followed by' + ' wildcard character in the beginning of path component followed by' +
' subpath.'); ' subpath.');
nfc_test(() => { nfc_test(() => {
return navigator.nfc.watch(noop, {url:""}); return navigator.nfc.watch(noop, {url:""});
}, 'Test that nfc.watch succeeds if NFCWatchOptions.url is empty.') }, 'Test that nfc.watch succeeds if NFCReaderOptions.url is empty.')
</script> </script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment