Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1182)

Unified Diff: third_party/WebKit/Source/modules/nfc/NFC.cpp

Issue 1759373003: [webnfc] Implement nfc.watch in blink nfc module. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@implement_nfc_push_in_android
Patch Set: Rebased. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/modules/nfc/NFC.cpp
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.cpp b/third_party/WebKit/Source/modules/nfc/NFC.cpp
index bc72ad1caa4e828e900dc0fde06e049ec16b7b58..86d008f888abc13ff40e974a525ef236a6fb950b 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.cpp
+++ b/third_party/WebKit/Source/modules/nfc/NFC.cpp
@@ -14,6 +14,7 @@
#include "modules/nfc/NFCError.h"
#include "modules/nfc/NFCMessage.h"
#include "modules/nfc/NFCPushOptions.h"
+#include "modules/nfc/NFCWatchOptions.h"
#include "platform/mojo/MojoHelper.h"
#include "public/platform/ServiceRegistry.h"
@@ -34,9 +35,14 @@ using device::wtf::NFCMessagePtr;
using device::wtf::NFCRecord;
using device::wtf::NFCRecordPtr;
using device::wtf::NFCRecordType;
+using device::wtf::NFCRecordTypeFilter;
+using device::wtf::NFCRecordTypeFilterPtr;
using device::wtf::NFCPushOptions;
using device::wtf::NFCPushOptionsPtr;
using device::wtf::NFCPushTarget;
+using device::wtf::NFCWatchMode;
+using device::wtf::NFCWatchOptions;
+using device::wtf::NFCWatchOptionsPtr;
NFCPushTarget toNFCPushTarget(const WTF::String& target)
{
@@ -70,6 +76,18 @@ NFCRecordType toNFCRecordType(const WTF::String& recordType)
return NFCRecordType::EMPTY;
}
+NFCWatchMode toNFCWatchMode(const WTF::String& watchMode)
+{
+ if (watchMode == "web-nfc-only")
+ return NFCWatchMode::WEBNFC_ONLY;
+
+ if (watchMode == "any")
+ return NFCWatchMode::ANY;
+
+ ASSERT_NOT_REACHED();
+ return NFCWatchMode::WEBNFC_ONLY;
+}
+
// https://w3c.github.io/web-nfc/#creating-web-nfc-message Step 2.1
// If NFCRecord type is not provided, deduct NFCRecord type from JS data type:
// String or Number => 'text' record
@@ -308,6 +326,31 @@ struct TypeConverter<NFCPushOptionsPtr, blink::NFCPushOptions> {
}
};
+template <>
+struct TypeConverter<NFCWatchOptionsPtr, blink::NFCWatchOptions> {
+ static NFCWatchOptionsPtr Convert(const blink::NFCWatchOptions& watchOptions)
+ {
+ // https://w3c.github.io/web-nfc/#the-nfcwatchoptions-dictionary
+ // Default values for NFCWatchOptions dictionary are:
+ // url = "", recordType = null, mediaType = "", mode = "web-nfc-only"
+ NFCWatchOptionsPtr watchOptionsPtr = NFCWatchOptions::New();
+ watchOptionsPtr->url = watchOptions.url();
+ watchOptionsPtr->mediaType = watchOptions.mediaType();
+
+ if (watchOptions.hasMode())
+ watchOptionsPtr->mode = toNFCWatchMode(watchOptions.mode());
+ else
+ watchOptionsPtr->mode = NFCWatchMode::WEBNFC_ONLY;
+
+ if (watchOptions.hasRecordType()) {
+ watchOptionsPtr->recordFilter = NFCRecordTypeFilter::New();
+ watchOptionsPtr->recordFilter->recordType = toNFCRecordType(watchOptions.recordType());
+ }
+
+ return watchOptionsPtr;
+ }
+};
+
} // namespace mojo
namespace blink {
@@ -430,23 +473,107 @@ bool setURL(const String& origin, device::wtf::NFCMessagePtr& message)
return originURL.isValid();
}
+String toNFCRecordType(const device::wtf::NFCRecordType& type)
+{
+ switch (type) {
+ case device::wtf::NFCRecordType::TEXT:
+ return "text";
+ case device::wtf::NFCRecordType::URL:
+ return "url";
+ case device::wtf::NFCRecordType::JSON:
+ return "json";
+ case device::wtf::NFCRecordType::OPAQUE_RECORD:
+ return "opaque";
+ case device::wtf::NFCRecordType::EMPTY:
+ return "empty";
+ }
+
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+v8::Local<v8::Value> toV8(const device::wtf::NFCRecordPtr& record, ScriptState* scriptState)
+{
+ switch (record->recordType) {
+ case device::wtf::NFCRecordType::TEXT:
+ case device::wtf::NFCRecordType::URL:
+ case device::wtf::NFCRecordType::JSON: {
+ String stringData;
+ if (!record->data.empty())
+ stringData = String::fromUTF8WithLatin1Fallback(static_cast<unsigned char*>(&record->data.front()), record->data.size());
+
+ if (record->recordType == device::wtf::NFCRecordType::JSON)
+ return v8::JSON::Parse(scriptState->isolate(), v8String(scriptState->isolate(), stringData)).ToLocalChecked();
+ return v8String(scriptState->isolate(), stringData);
+ }
+
+ case device::wtf::NFCRecordType::OPAQUE_RECORD: {
+ if (!record->data.empty()) {
+ DOMArrayBuffer* buffer = DOMArrayBuffer::create(static_cast<void*>(&record->data.front()), record->data.size());
+ return toV8(buffer, scriptState->context()->Global(), scriptState->isolate());
+ }
+
+ return v8::Null(scriptState->isolate());
+ }
+
+ case device::wtf::NFCRecordType::EMPTY:
+ return v8::Null(scriptState->isolate());
+ }
+
+ ASSERT_NOT_REACHED();
+ return v8::Local<v8::Value>();
+}
+
+NFCRecord toNFCRecord(const device::wtf::NFCRecordPtr& record, ScriptState* scriptState)
+{
+ NFCRecord nfcRecord;
+ nfcRecord.setMediaType(record->mediaType);
+ nfcRecord.setRecordType(toNFCRecordType(record->recordType));
+ nfcRecord.setData(ScriptValue(scriptState, toV8(record, scriptState)));
+ return nfcRecord;
+}
+
+NFCMessage toNFCMessage(const device::wtf::NFCMessagePtr& message, ScriptState* scriptState)
+{
+ NFCMessage nfcMessage;
+ nfcMessage.setURL(message->url);
+ blink::HeapVector<NFCRecord> records;
+ for (size_t i = 0; i < message->data.size(); ++i)
+ records.append(toNFCRecord(message->data[i], scriptState));
+ nfcMessage.setData(records);
+ return nfcMessage;
+}
+
} // anonymous namespace
-using NFCMojoCallback = mojo::Callback<void(device::wtf::NFCErrorPtr)>;
-class NFCCallback final : public NFCMojoCallback::Runnable {
- WTF_MAKE_NONCOPYABLE(NFCCallback);
+template <typename T>
+class NFCCallbackBase {
public:
- using NFCCallbackPromiseAdapter = CallbackPromiseAdapter<void, NFCError>;
- explicit NFCCallback(ScriptPromiseResolver* resolver)
- : m_promiseAdapter(adoptPtr(new NFCCallbackPromiseAdapter(resolver))) { }
+ explicit NFCCallbackBase(ScriptPromiseResolver* resolver)
+ : m_promiseAdapter(adoptPtr(new T(resolver))) { }
- ~NFCCallback() override
+ // If NFCService is not available or disappears when NFC HW is disabled,
+ // mojo service will invalidate proxy and destroy all pending callbacks.
+ // Promise will be rejected with NotSupportedError exception.
+ virtual ~NFCCallbackBase()
{
- // If NFCService is not available or disappears when NFC HW is disabled,
- // reject promise with NotSupportedError exception.
m_promiseAdapter->onError(device::wtf::NFCErrorType::NOT_SUPPORTED);
}
+protected:
+ OwnPtr<T> m_promiseAdapter;
+};
+
+using NFCMojoCallback = mojo::Callback<void(device::wtf::NFCErrorPtr)>;
+using NFCCallbackPromiseAdapter = CallbackPromiseAdapter<void, NFCError>;
+
+class NFCCallback final : public NFCMojoCallback::Runnable,
+ public NFCCallbackBase<NFCCallbackPromiseAdapter> {
+ WTF_MAKE_NONCOPYABLE(NFCCallback);
+public:
+ explicit NFCCallback(ScriptPromiseResolver* resolver)
+ : NFCCallbackBase<NFCCallbackPromiseAdapter>(resolver) { }
+
void Run(device::wtf::NFCErrorPtr error) override
{
if (error.is_null())
@@ -454,9 +581,33 @@ public:
else
m_promiseAdapter->onError(error->error_type);
}
+};
+
+using NFCWatchMojoCallback = mojo::Callback<void(uint32_t, device::wtf::NFCErrorPtr)>;
+using NFCWatchCallbackPromiseAdapter = CallbackPromiseAdapter<uint32_t, NFCError>;
+
+class NFCWatchCallback final : public NFCWatchMojoCallback::Runnable,
+ public NFCCallbackBase<NFCWatchCallbackPromiseAdapter> {
+ WTF_MAKE_NONCOPYABLE(NFCWatchCallback);
+public:
+ NFCWatchCallback(ScriptPromiseResolver* resolver, NFC* nfc, MessageCallback* callback)
+ : NFCCallbackBase<NFCWatchCallbackPromiseAdapter>(resolver)
+ , m_nfc(nfc)
+ , m_callback(callback) { }
+
+ void Run(uint32_t watchId, device::wtf::NFCErrorPtr error) override
+ {
+ if (error.is_null()) {
+ m_nfc->OnWatchRegistered(watchId, m_callback);
+ m_promiseAdapter->onSuccess(watchId);
+ } else {
+ m_promiseAdapter->onError(error->error_type);
+ }
+ }
private:
- OwnPtr<NFCCallbackPromiseAdapter> m_promiseAdapter;
+ Persistent<NFC> m_nfc;
+ Persistent<MessageCallback> m_callback;
};
NFC::NFC(LocalFrame* frame)
@@ -474,20 +625,17 @@ NFC* NFC::create(LocalFrame* frame)
NFC::~NFC() = default;
// https://w3c.github.io/web-nfc/#writing-or-pushing-content
+// https://w3c.github.io/web-nfc/#dom-nfc-push
ScriptPromise NFC::push(ScriptState* scriptState, const NFCPushMessage& pushMessage, const NFCPushOptions& options)
{
- String errorMessage;
- if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage));
- }
+ ScriptPromise promise = RejectIfNotSupported(scriptState);
+ if (!promise.isEmpty())
+ return promise;
DOMException* exception = isValidNFCPushMessage(pushMessage);
if (exception)
return ScriptPromise::rejectWithDOMException(scriptState, exception);
- if (!Initialize(scriptState->domWindow()->frame()->serviceRegistry()))
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
-
device::wtf::NFCMessagePtr message = device::wtf::NFCMessage::From(pushMessage);
if (!message)
return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SyntaxError));
@@ -501,15 +649,12 @@ ScriptPromise NFC::push(ScriptState* scriptState, const NFCPushMessage& pushMess
return resolver->promise();
}
+// https://w3c.github.io/web-nfc/#dom-nfc-cancelpush
ScriptPromise NFC::cancelPush(ScriptState* scriptState, const String& target)
{
- String errorMessage;
- if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage));
- }
-
- if (!Initialize(scriptState->domWindow()->frame()->serviceRegistry()))
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+ ScriptPromise promise = RejectIfNotSupported(scriptState);
+ if (!promise.isEmpty())
+ return promise;
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
m_nfc->CancelPush(mojo::toNFCPushTarget(target), device::wtf::NFC::CancelPushCallback(new NFCCallback(resolver)));
@@ -517,22 +662,49 @@ ScriptPromise NFC::cancelPush(ScriptState* scriptState, const String& target)
return resolver->promise();
}
+// https://w3c.github.io/web-nfc/#watching-for-content
+// https://w3c.github.io/web-nfc/#dom-nfc-watch
ScriptPromise NFC::watch(ScriptState* scriptState, MessageCallback* callback, const NFCWatchOptions& options)
{
- // TODO(shalamov): To be implemented.
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+ ScriptPromise promise = RejectIfNotSupported(scriptState);
+ if (!promise.isEmpty())
+ return promise;
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+ device::wtf::NFC::WatchCallback watchCallback(new NFCWatchCallback(resolver, this, callback));
+ m_nfc->Watch(device::wtf::NFCWatchOptions::From(options), watchCallback);
+ return resolver->promise();
}
+// https://w3c.github.io/web-nfc/#dom-nfc-cancelwatch
ScriptPromise NFC::cancelWatch(ScriptState* scriptState, long id)
{
- // TODO(shalamov): To be implemented.
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+ ScriptPromise promise = RejectIfNotSupported(scriptState);
+ if (!promise.isEmpty())
+ return promise;
+
+ if (id)
+ m_callbacks.remove(id);
+ else
+ return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotFoundError));
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+ m_nfc->CancelWatch(id, device::wtf::NFC::CancelWatchCallback(new NFCCallback(resolver)));
+ return resolver->promise();
}
+// https://w3c.github.io/web-nfc/#dom-nfc-cancelwatch
+// If watchId is not provided to nfc.cancelWatch, cancel all watch operations.
ScriptPromise NFC::cancelWatch(ScriptState* scriptState)
{
- // TODO(shalamov): To be implemented.
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+ ScriptPromise promise = RejectIfNotSupported(scriptState);
+ if (!promise.isEmpty())
+ return promise;
+
+ m_callbacks.clear();
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+ m_nfc->CancelAllWatches(device::wtf::NFC::CancelAllWatchesCallback(new NFCCallback(resolver)));
+ return resolver->promise();
}
void NFC::pageVisibilityChanged()
@@ -551,6 +723,12 @@ void NFC::pageVisibilityChanged()
void NFC::OnWatch(uint32_t id, device::wtf::NFCMessagePtr message)
{
+ WatchCallbacksMap::iterator it = m_callbacks.find(id);
+ if (it != m_callbacks.end()) {
+ ScriptState* scriptState = ScriptState::forMainWorld(toLocalFrame(page()->mainFrame()));
+ ScriptState::Scope scope(scriptState);
+ it->value->handleMessage(toNFCMessage(message, scriptState));
+ }
}
bool NFC::Initialize(ServiceRegistry* registry)
@@ -570,17 +748,37 @@ bool NFC::Initialize(ServiceRegistry* registry)
return m_nfc;
}
+ScriptPromise NFC::RejectIfNotSupported(ScriptState* scriptState)
+{
+ String errorMessage;
+ if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
+ return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage));
+ }
+
+ if (!Initialize(scriptState->domWindow()->frame()->serviceRegistry()))
+ return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+
+ return ScriptPromise();
+}
+
void NFC::OnError()
{
- // todo(shalamov): clear map that contains nfc watch callbacks
+ m_callbacks.clear();
if (m_client.is_bound())
m_client.Close();
m_nfc.reset();
}
+void NFC::OnWatchRegistered(uint32_t id, MessageCallback* callback)
+{
+ if (id)
+ m_callbacks.add(id, callback);
+}
+
DEFINE_TRACE(NFC)
{
PageLifecycleObserver::trace(visitor);
+ visitor->trace(m_callbacks);
}
} // namespace blink
« third_party/WebKit/LayoutTests/nfc/watch.html ('K') | « third_party/WebKit/Source/modules/nfc/NFC.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698