This patch adds initial implementation of W3C NFC API for Tizen platform.
API specification can be found here: http://www.w3.org/TR/nfc/
BUG=XWALK-432
--- /dev/null
+<html>
+<head>
+<title>NFC example</title>
+</head>
+<body>
+
+<button onclick='powerOn()'>Power ON</button>
+<button onclick='powerOff()'>Power OFF</button>
+<button onclick='startPoll()'>Start polling</button>
+<button onclick='stopPoll()'>Stop polling</button>
+
+<button onclick='createNDEFRecord()'>Create NDEF record</button>
+
+<div id='tag_methods' style='display: none;'>
+<button onclick='readNDEF()'>Read NDEF</button>
+<button onclick='writeTextNDEF()'>Write text NDEF</button>
+<button onclick='writeURINDEF()'>Write URI NDEF</button>
+<button onclick='writeMediaNDEF()'>Write Media NDEF</button>
+</div>
+
+<div id='peer_methods' style='display: none;'>
+<button onclick='sendURINDEF()'>Send URI NDEF to peer</button>
+</div>
+
+<div id='log'></div>
+<div id='eventLog'></div>
+
+<script>
+
+var tag = null;
+var peer = null;
+
+function addMessage(obj) {
+ if(typeof obj === 'string')
+ document.getElementById('log').innerHTML = obj;
+ else
+ document.getElementById('eventLog').innerHTML = "Received event: " + obj.type;
+}
+
+var events = [
+ 'poweron',
+ 'poweroff',
+ 'pollstart',
+ 'pollstop',
+ 'tagfound',
+ 'taglost',
+ 'peerfound',
+ 'peerlost'
+];
+
+function handleEvent(e) {
+ addMessage(e);
+}
+
+events.forEach(function(event) {
+ navigator.nfc.addEventListener(event, handleEvent);
+});
+
+navigator.nfc.addEventListener('tagfound', tagFound);
+navigator.nfc.addEventListener('taglost', tagLost);
+navigator.nfc.addEventListener('peerfound', peerFound);
+navigator.nfc.addEventListener('peerlost', peerLost);
+
+function tagFound(e) {
+ tag = e.tag;
+ document.getElementById('tag_methods').style.display = 'block';
+}
+
+function tagLost(e) {
+ tag = null;
+ document.getElementById('tag_methods').style.display = 'none';
+}
+
+function peerFound(e) {
+ peer = e.peer;
+ peer.addEventListener('messageread', onMessageRead);
+ document.getElementById('peer_methods').style.display = 'block';
+}
+
+function peerLost(e) {
+ peer = null;
+ document.getElementById('peer_methods').style.display = 'none';
+}
+
+function onMessageRead(e) {
+ addMessage("Received message: " + JSON.stringify(e.message));
+}
+
+function readNDEF() {
+ tag.readNDEF().then(function(record) {
+ addMessage("Read ndef: " + JSON.stringify(record));
+ }, function(){ addMessage("Cannot read tag"); });
+}
+
+function writeTextNDEF() {
+ var text = new NDEFRecordText("hello world", "en-US", "UTF-8");
+ tag.writeNDEF(new NDEFMessage([text])).then();
+}
+
+function writeURINDEF() {
+ var uri = new NDEFRecordURI("http://www.intel.com");
+ tag.writeNDEF(new NDEFMessage([uri])).then();
+}
+
+function sendURINDEF() {
+ var uri = new NDEFRecordURI("http://www.google.com");
+ peer.sendNDEF(new NDEFMessage([uri])).then();
+}
+
+function writeMediaNDEF() {
+ var media = new NDEFRecordMedia("text/plain", [104, 101, 108, 108, 111]);
+ tag.writeNDEF(new NDEFMessage([media])).then();
+}
+
+function createNDEFRecord() {
+ var uri = new NDEFRecordURI("http://www.intel.com");
+ uri.getPayload().then(function(res){ addMessage("payload: " + res); },
+ function(){ addMessage("getPayload Failed"); });
+}
+
+function powerOn() {
+ navigator.nfc.powerOn().then(function(){ addMessage("powerOn Succeeded"); },
+ function(){ addMessage("powerOn Failed"); });
+}
+
+function powerOff() {
+ navigator.nfc.powerOff().then(function(){ addMessage("powerOff Succeeded"); },
+ function(){ addMessage("powerOff Failed"); });
+}
+
+function startPoll() {
+ navigator.nfc.startPoll().then(function(){addMessage("startPoll Succeeded");},
+ function(){addMessage("startPoll Failed"); });
+}
+
+function stopPoll() {
+ navigator.nfc.stopPoll().then(function(){addMessage("stopPoll Succeeded");},
+ function(){addMessage("stopPoll Failed"); });
+}
+
+</script>
+
+</body>
+</html>
--- /dev/null
+## Introduction
+This folder contains implementation of NFC API for Crosswalk runtime.
+API specification can be located at http://www.w3.org/TR/nfc/
+
+Backend that provides core functionality is capi-network-nfc
\ No newline at end of file
--- /dev/null
+{
+ 'includes':[
+ '../common/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'tizen_nfc',
+ 'type': 'loadable_module',
+ 'variables': {
+ 'packages': [
+ 'capi-network-nfc',
+ ],
+ },
+ 'sources': [
+ 'nfc_api.js',
+ 'nfc_extension.cc',
+ 'nfc_extension.h',
+ 'nfc_instance.cc',
+ 'nfc_instance.h',
+ ],
+ 'includes': [
+ '../common/pkg-config.gypi',
+ ],
+ },
+ ],
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+
+var g_next_async_call_id = 1;
+var g_async_calls = {};
+var v8tools = requireNative('v8tools');
+var connected_peer_ = null;
+
+function AsyncCall(resolve, reject) {
+ this.resolve = resolve;
+ this.reject = reject;
+}
+
+function createPromise(msg) {
+ var promise = new Promise(function(resolve, reject) {
+ g_async_calls[g_next_async_call_id] = new AsyncCall(resolve, reject);
+ });
+ msg.asyncCallId = g_next_async_call_id;
+ extension.postMessage(JSON.stringify(msg));
+ ++g_next_async_call_id;
+ return promise;
+}
+
+function _addConstProperty(obj, propertyKey, propertyValue) {
+ if (typeof propertyValue !== 'undefined')
+ Object.defineProperty(obj, propertyKey, {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: propertyValue
+ });
+}
+
+function _addHiddenProperty(obj, propertyKey, propertyValue) {
+ Object.defineProperty(obj, propertyKey, {
+ enumerable: false,
+ writable: true,
+ value: propertyValue
+ });
+}
+
+function _addConstructorProperty(obj, constructor) {
+ Object.defineProperty(obj, 'constructor', {
+ enumerable: false,
+ value: constructor
+ });
+}
+
+function derive(child, parent) {
+ child.prototype = Object.create(parent.prototype);
+ child.prototype.constructor = child;
+ _addConstructorProperty(child.prototype, child);
+}
+
+function EventTargetInterface(eventListeners, isValidType) {
+ _addHiddenProperty(this, 'listeners_', eventListeners);
+ _addHiddenProperty(this, 'isValidType_', isValidType);
+}
+
+EventTargetInterface.prototype.addEventListener = function(type, callback) {
+ if (callback != null && typeof callback === 'function' &&
+ this.isValidType_(type))
+ if (~~this.listeners_[type].indexOf(callback))
+ this.listeners_[type].push(callback);
+};
+
+EventTargetInterface.prototype.removeEventListener = function(type, callback) {
+ if (callback != null &&
+ typeof callback === 'function' && this.isValidType_(type)) {
+ var index = this.listeners_[type].indexOf(callback);
+ if (~index)
+ this.listeners_[type].slice(index, 1);
+ }
+};
+
+EventTargetInterface.prototype.dispatchEvent = function(event) {
+ var handled = true;
+
+ if (typeof event !== 'object' || !this.isValidType_(event.type))
+ return false;
+
+ this.listeners_[event.type].forEach(function(callback) {
+ var res = callback(event);
+ if (!res && handled)
+ handled = false;
+ });
+
+ return handled;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extension message listener
+///////////////////////////////////////////////////////////////////////////////
+
+extension.setMessageListener(function(json) {
+ var msg = JSON.parse(json);
+ switch (msg.cmd) {
+ case 'poweron':
+ v8tools.forceSetProperty(g_nfc_manager, 'powered', true);
+ break;
+ case 'poweroff':
+ v8tools.forceSetProperty(g_nfc_manager, 'powered', false);
+ break;
+ case 'pollstart':
+ v8tools.forceSetProperty(g_nfc_manager, 'polling', true);
+ break;
+ case 'pollstop':
+ v8tools.forceSetProperty(g_nfc_manager, 'polling', false);
+ break;
+ case 'messageread':
+ handleMessageRead(msg);
+ break;
+ case 'readNDEF':
+ handleReadNDEF(msg);
+ break;
+ case 'sendNDEF':
+ handleAsyncCallSuccess(msg.asyncCallId);
+ break;
+ case 'getPayload':
+ handleAsyncCallSuccess(msg.asyncCallId, msg.result);
+ break;
+ case 'asyncCallError':
+ handleAsyncCallError(msg);
+ break;
+ default:
+ console.log('Received unknown command');
+ break;
+ }
+
+ if (msg.cmd in NFCManagerEventNames)
+ handleEvent(msg);
+});
+
+///////////////////////////////////////////////////////////////////////////////
+// NFCManager
+///////////////////////////////////////////////////////////////////////////////
+
+var NFCManagerEventNames = {
+ poweron: 0,
+ poweroff: 1,
+ pollstart: 2,
+ pollstop: 3,
+ tagfound: 4,
+ taglost: 5,
+ peerfound: 6,
+ peerlost: 7
+};
+
+function handleEvent(msg) {
+ if (msg.asyncCallId in g_async_calls) {
+ g_async_calls[msg.asyncCallId].resolve();
+ delete g_async_calls[msg.asyncCallId];
+ }
+ dispatchEventForName(msg.cmd);
+}
+
+function handleAsyncCallSuccess(callId, result) {
+ if (callId in g_async_calls) {
+ g_async_calls[callId].resolve(result);
+ delete g_async_calls[callId];
+ }
+}
+
+function toNDEFRecord(rec) {
+ var ndef = null;
+ switch (rec.recordType) {
+ case 'text':
+ ndef = new NDEFRecordText(rec.text, rec.languageCode, rec.encoding);
+ break;
+ case 'uri':
+ ndef = new NDEFRecordURI(rec.uri);
+ break;
+ case 'media':
+ ndef = new NDEFRecordMedia(rec.mimeType, rec.payload);
+ break;
+ case 'smartPoster':
+ default:
+ ndef = new NDEFRecord(rec.recordType, rec.tnf,
+ rec.type, rec.payload, rec.id);
+ break;
+ }
+ v8tools.forceSetProperty(ndef, 'payload', rec.payload);
+ return ndef;
+}
+
+function handleReadNDEF(msg) {
+ handleAsyncCallSuccess(msg.asyncCallId, toNDEFRecord(msg.result[0]));
+}
+
+function handleAsyncCallError(msg) {
+ if (msg.asyncCallId in g_async_calls) {
+ g_async_calls[msg.asyncCallId].reject(Error('Async operation failed'));
+ delete g_async_calls[msg.asyncCallId];
+ }
+}
+
+function dispatchEventForName(eventName) {
+ var event = new CustomEvent(eventName);
+ if (eventName === 'tagfound')
+ _addConstProperty(event, 'tag', new NFCTag());
+ else if (eventName === 'peerfound')
+ _addConstProperty(event, 'peer', connected_peer_ = new NFCPeer());
+ else if (eventName === 'peerlost')
+ connected_peer_ = null;
+ dispatchEvent(event, eventName);
+}
+
+function dispatchEvent(event, eventName) {
+ g_nfc_manager.dispatchEvent(event);
+ if (g_nfc_manager[eventName] &&
+ typeof g_nfc_manager[eventName] === 'function')
+ g_nfc_manager[eventName](event);
+}
+
+function NFCManager() {
+ var nfc_manager_listeners = {};
+ for (var key in NFCManagerEventNames)
+ nfc_manager_listeners[key] = [];
+
+ EventTargetInterface.call(this,
+ nfc_manager_listeners,
+ function(type) {return type in NFCManagerEventNames;});
+ var is_powered = JSON.parse(extension.internal.sendSyncMessage(
+ JSON.stringify({cmd: 'is_powered'})));
+ _addConstProperty(this, 'powered', is_powered);
+ _addConstProperty(this, 'polling', false);
+ this.onpoweron = null;
+ this.onpoweroff = null;
+ this.onpollstart = null;
+ this.onpollstop = null;
+ this.ontagfound = null;
+ this.ontaglost = null;
+ this.onpeerfound = null;
+ this.onpeerlost = null;
+}
+derive(NFCManager, EventTargetInterface);
+
+NFCManager.prototype.powerOn = function() {
+ return createPromise({'cmd': 'poweron'});
+};
+
+NFCManager.prototype.powerOff = function() {
+ return createPromise({'cmd': 'poweroff'});
+};
+
+NFCManager.prototype.startPoll = function() {
+ return createPromise({'cmd': 'pollstart'});
+};
+
+NFCManager.prototype.stopPoll = function() {
+ return createPromise({'cmd': 'pollstop'});
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NFCTag
+///////////////////////////////////////////////////////////////////////////////
+
+function NFCTag() {}
+
+NFCTag.prototype.readNDEF = function() {
+ return createPromise({'cmd': 'readNDEF'});
+};
+
+// NDEFMessage message
+NFCTag.prototype.writeNDEF = function(message) {
+ var msg = {
+ 'cmd': 'writeNDEF',
+ 'message': message
+ };
+ return createPromise(msg);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NFCPeer
+///////////////////////////////////////////////////////////////////////////////
+
+function NFCPeer() {
+ var nfc_peer_listeners = {};
+ nfc_peer_listeners['messageread'] = [];
+ EventTargetInterface.call(this,
+ nfc_peer_listeners, function(type) { return type === 'messageread';});
+ this.onmessageread = null;
+}
+derive(NFCPeer, EventTargetInterface);
+
+// NDEFMessage message
+NFCPeer.prototype.sendNDEF = function(message) {
+ var msg = {
+ 'cmd': 'sendNDEF',
+ 'message': message
+ };
+ return createPromise(msg);
+};
+
+// HandoverType handoverType
+NFCPeer.prototype.startHandover = function(handoverType) {
+ var msg = {
+ 'cmd': 'startHandover',
+ 'handoverType': handoverType
+ };
+ return createPromise(msg);
+};
+
+function handleMessageRead(msg) {
+ if (connected_peer_ !== null) {
+ var ndefRecords = [];
+ msg.result.forEach(function(record) {
+ ndefRecords.push(toNDEFRecord(record));
+ });
+ var event = new CustomEvent('messageread');
+ var ndefMessage = new NDEFMessage(ndefRecords);
+ _addConstProperty(event, 'message', ndefMessage);
+ connected_peer_.dispatchEvent(event);
+ if (connected_peer_.onmessageread &&
+ typeof connected_peer_.onmessageread === 'function')
+ connected_peer_.onmessageread(ndefMessage);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFMessage
+///////////////////////////////////////////////////////////////////////////////
+
+function NDEFMessage(data) {
+ var records = data;
+ if (Array.isArray(data) && data.length > 0 &&
+ typeof data[0] === 'number')
+ records = [new NDEFRecord('unknown', 5, null, data)];
+ _addConstProperty(this, 'records', records);
+}
+
+NDEFMessage.prototype.getBytes = function() {
+ var msg = {
+ 'cmd': 'getBytes',
+ 'records': records
+ };
+ return createPromise(msg);
+};
+
+window.NDEFMessage = NDEFMessage;
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFRecord
+// TNF types:
+// 0 (Empty), 1 (Well known), 2 (Media), 3 (URI), 4 (External), 5 (Unknown)
+///////////////////////////////////////////////////////////////////////////////
+
+// NDEFRecordType recordType
+// byte tnf
+// DOMString type
+// byte array
+// DOMString id
+
+function NDEFRecord(recordType, tnf, type, payload, id) {
+ _addConstProperty(this, 'recordType', recordType);
+ _addConstProperty(this, 'tnf', tnf);
+ _addConstProperty(this, 'type', type);
+ _addConstProperty(this, 'payload', payload);
+ _addConstProperty(this, 'id', id);
+}
+
+NDEFRecord.prototype.getPayload = function() {
+ var msg = {
+ 'cmd': 'getPayload',
+ 'record': this
+ };
+ return createPromise(msg);
+};
+
+window.NDEFRecord = NDEFRecord;
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFRecordText
+///////////////////////////////////////////////////////////////////////////////
+
+function NDEFRecordText(text, languageCode, encoding) {
+ NDEFRecord.call(this, 'text', 1, 'T');
+ _addConstProperty(this, 'text', text);
+ _addConstProperty(this, 'languageCode', languageCode);
+ _addConstProperty(this, 'encoding', encoding);
+}
+
+derive(NDEFRecordText, NDEFRecord);
+window.NDEFRecordText = NDEFRecordText;
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFRecordURI
+///////////////////////////////////////////////////////////////////////////////
+
+// DOMString uri
+function NDEFRecordURI(uri) {
+ NDEFRecord.call(this, 'uri', 1, 'U');
+ _addConstProperty(this, 'uri', uri);
+}
+
+derive(NDEFRecordURI, NDEFRecord);
+window.NDEFRecordURI = NDEFRecordURI;
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFRecordMedia
+///////////////////////////////////////////////////////////////////////////////
+
+// DOMString mimeType
+// byte array payload
+function NDEFRecordMedia(mimeType, payload) {
+ NDEFRecord.call(this, 'media', 2, mimeType, payload);
+ _addConstProperty(this, 'mimeType', mimeType);
+}
+
+derive(NDEFRecordMedia, NDEFRecord);
+window.NDEFRecordMedia = NDEFRecordMedia;
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFRecordSmartPoster
+///////////////////////////////////////////////////////////////////////////////
+
+// constructor
+// DOMString uri,
+// optional NDEFRecordText array titles,
+// optional DOMString action,
+// optional NDEFRecordMedia array icons,
+// optional unsigned long targetSize,
+// optional DOMString targetMIME
+
+function NDEFRecordSmartPoster(uri, titles, action,
+ icons, targetSize, targetMIME) {
+ NDEFRecord.call(this, 'smartPoster', 3, 'Sp');
+ _addConstProperty(this, 'uri', uri);
+ _addConstProperty(this, 'titles', titles);
+ _addConstProperty(this, 'action', action);
+ _addConstProperty(this, 'icons', icons);
+ _addConstProperty(this, 'targetSize', targetSize);
+ _addConstProperty(this, 'targetMIME', targetMIME);
+}
+
+derive(NDEFRecordSmartPoster, NDEFRecord);
+window.NDEFRecordSmartPoster = NDEFRecordSmartPoster;
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - NDEFRecordType
+///////////////////////////////////////////////////////////////////////////////
+
+var NDEFRecordType = {
+ text: 0,
+ uri: 1,
+ media: 2,
+ smartPoster: 3,
+ unknown: 4
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - SmartPosterAction
+///////////////////////////////////////////////////////////////////////////////
+
+var SmartPosterAction = {
+ do: 0,
+ save: 1,
+ open: 2
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// NFC - HandoverType
+///////////////////////////////////////////////////////////////////////////////
+
+var HandoverType = {
+ wifi: 0,
+ bluetooth: 1
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// NFCManager - Instance
+///////////////////////////////////////////////////////////////////////////////
+
+var g_nfc_manager = new NFCManager();
+exports = g_nfc_manager;
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NFC_NFC_CALLBACKS_H_
+#define NFC_NFC_CALLBACKS_H_
+
+#include <string>
+
+typedef struct _ndef_message_s *nfc_ndef_message_h;
+
+struct CallbackData {
+ CallbackData(void* data, double async_id,
+ const std::string& event_name, nfc_ndef_message_h message = 0)
+ : data_(data),
+ async_id_(async_id),
+ event_name_(event_name),
+ message_(message) {}
+ void* data_;
+ double async_id_;
+ std::string event_name_;
+ nfc_ndef_message_h message_;
+};
+
+#define CALLBACK_METHOD(METHOD, ARG0, DATA_TYPE) \
+ static void METHOD ## CallBack(ARG0 res, void* userdata) { \
+ reinterpret_cast<DATA_TYPE*>(userdata)->METHOD(res); \
+ } \
+ \
+ void METHOD(ARG0);
+
+#define CALLBACK_METHOD_2(METHOD, ARG0, ARG1, DATA_TYPE) \
+ static void METHOD ## CallBack(ARG0 arg0, ARG1 arg1, void* userdata) { \
+ reinterpret_cast<DATA_TYPE*>(userdata)->METHOD(arg0, arg1); \
+ } \
+ \
+ void METHOD(ARG0, ARG1);
+
+#define CALLBACK_METHOD_WITH_DATA(METHOD, ARG0, DATA_TYPE) \
+ static void METHOD ## CallBack(ARG0 res, void* userdata) { \
+ CallbackData* d = static_cast<CallbackData*>(userdata); \
+ DATA_TYPE* data = reinterpret_cast<DATA_TYPE*>(d->data_); \
+ data->METHOD(res, d); \
+ delete d; \
+ } \
+ \
+ void METHOD(ARG0, CallbackData* cd);
+
+#define CALLBACK_METHOD_WITH_DATA_2(METHOD, ARG0, ARG1, DATA_TYPE) \
+ static void METHOD ## CallBack(ARG0 arg0, ARG1 arg1, void* userdata) { \
+ CallbackData* d = static_cast<CallbackData*>(userdata); \
+ DATA_TYPE* data = reinterpret_cast<DATA_TYPE*>(d->data_); \
+ data->METHOD(arg0, arg1, d); \
+ delete d; \
+ } \
+ \
+ void METHOD(ARG0, ARG1, CallbackData* cd);
+
+#endif // NFC_NFC_CALLBACKS_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "nfc/nfc_extension.h"
+
+#include "nfc/nfc_instance.h"
+
+common::Extension* CreateExtension() {
+ return new NfcExtension;
+}
+
+extern const char kSource_nfc_api[];
+
+NfcExtension::NfcExtension() {
+ SetExtensionName("navigator.nfc");
+ SetJavaScriptAPI(kSource_nfc_api);
+ const char* entry_points[] = {
+ "window.NDEFMessage",
+ "window.NDEFRecord",
+ "window.NDEFRecordText",
+ "window.NDEFRecordURI",
+ "window.NDEFRecordMedia",
+ "window.NDEFRecordSmartPoster",
+ NULL
+ };
+ SetExtraJSEntryPoints(entry_points);
+}
+
+NfcExtension::~NfcExtension() {}
+
+common::Instance* NfcExtension::CreateInstance() {
+ return new NfcInstance;
+}
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NFC_NFC_EXTENSION_H_
+#define NFC_NFC_EXTENSION_H_
+
+#include "common/extension.h"
+
+class NfcExtension : public common::Extension {
+ public:
+ NfcExtension();
+ virtual ~NfcExtension();
+
+ private:
+ // common::Extension implementation.
+ virtual common::Instance* CreateInstance();
+};
+
+#endif // NFC_NFC_EXTENSION_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "nfc/nfc_instance.h"
+
+#include <string>
+
+#include "common/picojson.h"
+
+namespace {
+
+const char kTypeText[] = "T";
+const char kTypeSmartPoster[] = "Sp";
+const char kTypeUri[] = "U";
+const char kTypeMime[] = "mime";
+const char kTypeAlternativeCarrier[] = "ac";
+const char kTypeHandoverCarrier[] = "Hc";
+const char kTypeHandoverRequest[] = "Hr";
+const char kTypeHandoverSelect[] = "Hs";
+
+const char kJSTypeText[] = "text";
+const char kJSTypeUri[] = "uri";
+const char kJSTypeMedia[] = "media";
+const char kJSTypeSmartPoster[] = "smartPoster";
+const char kJSTypeUnknown[] = "unknown";
+
+std::string NfcRecordTypeToJsType(const std::string& type) {
+ if (type == kTypeText)
+ return kJSTypeText;
+ else if (type == kTypeSmartPoster)
+ return kJSTypeSmartPoster;
+ else if (type == kTypeUri)
+ return kJSTypeUri;
+ else if (type == kTypeMime)
+ return kJSTypeMedia;
+ else if (type.empty())
+ return kJSTypeUnknown;
+ else
+ return type;
+}
+
+void SetTextProperties(nfc_ndef_record_h record,
+ picojson::object& out_value) {
+ char* text = NULL;
+ if (nfc_ndef_record_get_text(record, &text) == NFC_ERROR_NONE)
+ out_value["text"] = picojson::value(text);
+
+ char* lang_code = NULL;
+ if (nfc_ndef_record_get_langcode(record, &lang_code) == NFC_ERROR_NONE)
+ out_value["languageCode"] = picojson::value(lang_code);
+
+ nfc_encode_type_e encode;
+ if (nfc_ndef_record_get_encode_type(record, &encode) == NFC_ERROR_NONE)
+ out_value["encoding"] =
+ picojson::value(encode == NFC_ENCODE_UTF_8 ? "UTF-8" : "UTF-16");
+}
+
+void SetUriProperties(nfc_ndef_record_h record,
+ picojson::object& out_value) {
+ char* uri = NULL;
+ if (nfc_ndef_record_get_uri(record, &uri) == NFC_ERROR_NONE) {
+ out_value["uri"] = picojson::value(uri);
+ free(uri);
+ }
+}
+
+void SetMIMEProperties(nfc_ndef_record_h record,
+ picojson::object& out_value) {
+ char* mime_type = NULL;
+ if (nfc_ndef_record_get_mime_type(record, &mime_type) == NFC_ERROR_NONE) {
+ out_value["mimeType"] = picojson::value(mime_type);
+ free(mime_type);
+ }
+}
+
+void SetType(const std::string& type, picojson::object& out_value) {
+ out_value["recordType"] = picojson::value(NfcRecordTypeToJsType(type));
+}
+
+void SetTnf(nfc_record_tnf_e tnf, picojson::object& out_value) {
+ out_value["tnf"] = picojson::value(static_cast<double>(tnf));
+}
+
+void SetId(nfc_ndef_record_h record, picojson::object& out_value) {
+ unsigned char* id = NULL;
+ int id_size = 0;
+ int err = nfc_ndef_record_get_id(record, &id, &id_size);
+ if (err == NFC_ERROR_NONE && id_size > 0)
+ out_value["id"] =
+ picojson::value(std::string(reinterpret_cast<char*>(id), id_size));
+}
+
+void SetPayload(nfc_ndef_record_h record, picojson::object& out_value) {
+ unsigned char* payload = NULL;
+ unsigned int payload_size = 0;
+ int err = nfc_ndef_record_get_payload(record, &payload, &payload_size);
+ if (err == NFC_ERROR_NONE) {
+ picojson::array array;
+ for (int i = 0; i < payload_size; i++)
+ array.push_back(picojson::value(static_cast<double>(payload[i])));
+ out_value["payload"] = picojson::value(array);
+ }
+}
+
+int NdefRecordToJson(nfc_ndef_record_h record,
+ picojson::value& out_value) {
+ picojson::object json_record;
+ nfc_record_tnf_e tnf;
+ int ret = nfc_ndef_record_get_tnf(record, &tnf);
+ if (ret != NFC_ERROR_NONE)
+ return ret;
+
+ unsigned char* type = 0;
+ int type_size = 0;
+ nfc_ndef_record_get_type(record, &type, &type_size);
+
+ std::string type_str(reinterpret_cast<char*>(type), type_size);
+ SetType(type_str, json_record);
+ SetTnf(tnf, json_record);
+ SetId(record, json_record);
+ SetPayload(record, json_record);
+
+ switch (tnf) {
+ case NFC_RECORD_TNF_WELL_KNOWN:
+ if (type_str == kTypeText)
+ SetTextProperties(record, json_record);
+ else if (type_str == kTypeUri)
+ SetUriProperties(record, json_record);
+ break;
+ case NFC_RECORD_TNF_MIME_MEDIA:
+ SetType(kJSTypeMedia, json_record);
+ SetMIMEProperties(record, json_record);
+ break;
+ case NFC_RECORD_TNF_URI:
+ SetUriProperties(record, json_record);
+ break;
+ }
+
+ if (ret == NFC_ERROR_NONE)
+ out_value = picojson::value(json_record);
+
+ return ret;
+}
+
+int NdefMessageToJson(nfc_ndef_message_h message,
+ picojson::value& out_value) {
+ picojson::value::array records;
+ int record_count = 0;
+ int ret = nfc_ndef_message_get_record_count(message, &record_count);
+ if (ret == NFC_ERROR_NONE) {
+ for (int i = 0; i < record_count; i++) {
+ nfc_ndef_record_h record = NULL;
+ ret = nfc_ndef_message_get_record(message, i, &record);
+ picojson::value json_record;
+ if (ret == NFC_ERROR_NONE
+ && NdefRecordToJson(record, json_record) == NFC_ERROR_NONE)
+ records.push_back(json_record);
+ else
+ break;
+ }
+ }
+
+ if (ret == NFC_ERROR_NONE)
+ out_value = picojson::value(records);
+ return ret;
+}
+
+int CreateTextRecord(nfc_ndef_record_h* out_ndef_record,
+ const picojson::value& record) {
+ return nfc_ndef_record_create_text(out_ndef_record,
+ record.get("text").to_str().c_str(),
+ record.get("languageCode").to_str().c_str(),
+ record.get("encoding").to_str() == "UTF-8" ? NFC_ENCODE_UTF_8
+ : NFC_ENCODE_UTF_16);
+}
+
+int CreateUriRecord(nfc_ndef_record_h* out_ndef_record,
+ const picojson::value& record) {
+ return nfc_ndef_record_create_uri(out_ndef_record,
+ record.get("uri").to_str().c_str());
+}
+
+int CreateMediaRecord(nfc_ndef_record_h* out_ndef_record,
+ const picojson::value& record) {
+ picojson::array payload = record.get("payload").get<picojson::array>();
+ size_t payload_size = payload.size();
+ unsigned char* data = new unsigned char[payload_size];
+
+ for (size_t i = 0; i < payload_size; i++)
+ data[i] = static_cast<unsigned char>(payload[i].get<double>());
+
+ int ret = nfc_ndef_record_create_mime(out_ndef_record,
+ record.get("mimeType").to_str().c_str(), data, payload_size);
+
+ delete[] data;
+ return ret;
+}
+
+int JsonRecordToNdefRecord(const picojson::value& record,
+ nfc_ndef_record_h* out_ndef_record) {
+ if (!record.is<picojson::object>())
+ return NFC_ERROR_INVALID_PARAMETER;
+
+ int ret = NFC_ERROR_NONE;
+ std::string recordType = record.get("recordType").to_str();
+ if (recordType == kJSTypeText)
+ ret = CreateTextRecord(out_ndef_record, record);
+ else if (recordType == kJSTypeUri)
+ ret = CreateUriRecord(out_ndef_record, record);
+ else if (recordType == kJSTypeMedia)
+ ret = CreateMediaRecord(out_ndef_record, record);
+ else if (recordType == kJSTypeSmartPoster)
+ // TODO(shalamov): Not implemented.
+ ret = NFC_ERROR_INVALID_PARAMETER;
+ else if (recordType == kJSTypeUnknown)
+ // TODO(shalamov): Not implemented.
+ ret = NFC_ERROR_INVALID_PARAMETER;
+
+ return ret;
+}
+
+int JsonMessageToNdefMessage(const picojson::value& message,
+ nfc_ndef_message_h* out_ndef_message) {
+ if (!message.is<picojson::array>())
+ return NFC_ERROR_INVALID_PARAMETER;
+
+ int ret = nfc_ndef_message_create(out_ndef_message);
+ if (ret != NFC_ERROR_NONE)
+ return ret;
+
+ picojson::array records = message.get<picojson::array>();
+ picojson::array::const_iterator it = records.begin();
+ picojson::array::const_iterator end = records.end();
+ while (it != end) {
+ nfc_ndef_record_h ndef_record = NULL;
+ ret = JsonRecordToNdefRecord(*it, &ndef_record);
+ if (ret == NFC_ERROR_NONE) {
+ ret = nfc_ndef_message_append_record(*out_ndef_message, ndef_record);
+ it++;
+ } else {
+ nfc_ndef_message_destroy(*out_ndef_message);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+} // namespace
+
+NfcInstance::NfcInstance()
+ : nfc_manager_activated_(nfc_manager_is_activated()) {
+ nfc_manager_init_code_ = nfc_manager_initialize_sync();
+ nfc_manager_set_activation_changed_cb(OnActivationChangedCallBack, this);
+}
+
+NfcInstance::~NfcInstance() {
+}
+
+void NfcInstance::HandleMessage(const char* message) {
+ picojson::value v;
+
+ std::string err;
+ picojson::parse(v, message, message + strlen(message), &err);
+ if (!err.empty())
+ return;
+
+ if (nfc_manager_init_code_) {
+ PostError(v.get("asyncCallId").get<double>());
+ return;
+ }
+
+ std::string cmd = v.get("cmd").to_str();
+ if (cmd == "poweron")
+ SwitchPower(true, v);
+ else if (cmd == "poweroff")
+ SwitchPower(false, v);
+ else if (cmd == "pollstart")
+ PollStart(v);
+ else if (cmd == "pollstop")
+ PollStop(v);
+ else if (cmd == "readNdef")
+ ReadNdef(v);
+ else if (cmd == "writeNdef")
+ WriteNdef(v);
+ else if (cmd == "sendNdef")
+ SendNdef(v);
+ else if (cmd == "startHandover")
+ StartHandover(v);
+ else if (cmd == "getBytes")
+ GetBytes(v);
+ else if (cmd == "getPayload")
+ GetPayload(v);
+ else
+ std::cerr << "Received unknown message: " << cmd << "\n";
+}
+
+void NfcInstance::HandleSyncMessage(const char* message) {
+ picojson::value v;
+
+ std::string err;
+ picojson::parse(v, message, message + strlen(message), &err);
+ if (!err.empty()) {
+ return;
+ }
+
+ std::string cmd = v.get("cmd").to_str();
+ if (cmd == "is_powered")
+ SendSyncReply(picojson::value(nfc_manager_activated_).to_str().c_str());
+ else
+ std::cerr << "Ignoring unknown command: " << cmd;
+}
+
+void NfcInstance::SwitchPower(bool state, const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+ CallbackData* cd =
+ new CallbackData(this, async_call_id, value.get("cmd").to_str());
+ int ret = nfc_manager_set_activation(state, OnPoweredCallBack, cd);
+ if (ret != NFC_ERROR_NONE) {
+ PostError(async_call_id);
+ delete cd;
+ }
+}
+
+void NfcInstance::PollStart(const picojson::value& value) {
+ nfc_manager_set_tag_discovered_cb(OnTagDiscoveredCallBack, this);
+ nfc_manager_set_p2p_target_discovered_cb(OnP2PDiscoveredCallBack, this);
+ PostSuccess("pollstart", value.get("asyncCallId").get<double>());
+}
+
+void NfcInstance::PollStop(const picojson::value& value) {
+ nfc_manager_unset_tag_discovered_cb();
+ nfc_manager_unset_p2p_target_discovered_cb();
+ PostSuccess("pollstop", value.get("asyncCallId").get<double>());
+}
+
+void NfcInstance::ReadNdef(const picojson::value& value) {
+ double async_id = value.get("asyncCallId").get<double>();
+ int ret = NFC_ERROR_NONE;
+ if (attached_tag_) {
+ bool ndef_supported = false;
+ ret = nfc_tag_is_support_ndef(attached_tag_, &ndef_supported);
+ if (ret == NFC_ERROR_NONE && ndef_supported) {
+ CallbackData* cd = new CallbackData(this, async_id, "readNdef");
+ ret = nfc_tag_read_ndef(attached_tag_, OnReadNdefCallBack, cd);
+ if (ret != NFC_ERROR_NONE)
+ delete cd;
+ }
+ }
+
+ if (ret != NFC_ERROR_NONE)
+ PostError(async_id);
+}
+
+void NfcInstance::WriteNdef(const picojson::value& value) {
+ double async_id = value.get("asyncCallId").get<double>();
+ nfc_ndef_message_h ndef_message = NULL;
+ picojson::value message = value.get("message");
+ int ret = JsonMessageToNdefMessage(message.get("records"), &ndef_message);
+ if (ret == NFC_ERROR_NONE) {
+ CallbackData* cd =
+ new CallbackData(this, async_id, "writeNdef", ndef_message);
+ ret = nfc_tag_write_ndef(attached_tag_, ndef_message,
+ OnWriteNdefCallBack, cd);
+ if (ret != NFC_ERROR_NONE) {
+ nfc_ndef_message_destroy(ndef_message);
+ delete cd;
+ }
+ }
+
+ if (ret != NFC_ERROR_NONE)
+ PostError(async_id);
+}
+
+void NfcInstance::SendNdef(const picojson::value& value) {
+ double async_id = value.get("asyncCallId").get<double>();
+ nfc_ndef_message_h ndef_message = NULL;
+ picojson::value message = value.get("message");
+ int ret = JsonMessageToNdefMessage(message.get("records"), &ndef_message);
+ if (ret == NFC_ERROR_NONE) {
+ CallbackData* cd =
+ new CallbackData(this, async_id, "sendNdef", ndef_message);
+ ret = nfc_p2p_send(connected_peer_, ndef_message,
+ OnP2PMessageSentCallBack, cd);
+ if (ret != NFC_ERROR_NONE) {
+ nfc_ndef_message_destroy(ndef_message);
+ delete cd;
+ }
+ }
+
+ if (ret != NFC_ERROR_NONE)
+ PostError(async_id);
+}
+
+void NfcInstance::StartHandover(const picojson::value& value) {
+ // TODO(shalamov): Not implemented.
+}
+
+void NfcInstance::GetBytes(const picojson::value& value) {
+ // TODO(shalamov): Not implemented.
+}
+
+void NfcInstance::GetPayload(const picojson::value& value) {
+ double async_id = value.get("asyncCallId").get<double>();
+ if (value.contains("record")
+ && value.get("record").contains("payload")) {
+ PostResult("getPayload",
+ value.get("record").get("payload"), async_id);
+ } else {
+ nfc_ndef_record_h out_ndef_record;
+ int ret = JsonRecordToNdefRecord(value.get("record"), &out_ndef_record);
+ if (ret == NFC_ERROR_NONE) {
+ picojson::object payload;
+ SetPayload(out_ndef_record, payload);
+ nfc_ndef_record_destroy(out_ndef_record);
+ PostResult("getPayload", picojson::value(payload["payload"]), async_id);
+ } else {
+ PostError(async_id);
+ }
+ }
+}
+
+void NfcInstance::PostError(double async_operation_id) {
+ PostResult("asyncCallError", async_operation_id);
+}
+
+void NfcInstance::PostSuccess(const std::string& event,
+ double async_operation_id) {
+ PostResult(event, async_operation_id);
+}
+
+void NfcInstance::PostResult(
+ const std::string& command,
+ double async_operation_id) {
+ picojson::value::object object;
+ object["cmd"] = picojson::value(command);
+ object["asyncCallId"] = picojson::value(async_operation_id);
+ picojson::value value(object);
+ PostMessage(value.serialize().c_str());
+}
+
+void NfcInstance::PostResult(
+ const std::string& command,
+ const picojson::value& result,
+ double async_operation_id) {
+ picojson::value::object object;
+ object["cmd"] = picojson::value(command);
+ object["result"] = picojson::value(result);
+ object["asyncCallId"] = picojson::value(async_operation_id);
+ picojson::value value(object);
+ PostMessage(value.serialize().c_str());
+}
+
+void NfcInstance::OnActivationChanged(bool activated) {
+ nfc_manager_activated_ = activated;
+ nfc_manager_activated_ ? PostSuccess("poweron") :
+ PostSuccess("poweroff");
+}
+
+void NfcInstance::OnPowered(nfc_error_e error, CallbackData* cd) {
+ error == NFC_ERROR_NONE ? PostSuccess(cd->event_name_, cd->async_id_)
+ : PostError(cd->async_id_);
+}
+
+void NfcInstance::OnTagDiscovered(nfc_discovered_type_e type, nfc_tag_h tag) {
+ if (type == NFC_DISCOVERED_TYPE_ATTACHED) {
+ attached_tag_ = tag;
+ PostSuccess("tagfound");
+ } else {
+ attached_tag_ = NULL;
+ PostSuccess("taglost");
+ }
+}
+
+void NfcInstance::OnP2PDiscovered(nfc_discovered_type_e type,
+ nfc_p2p_target_h target) {
+ if (type == NFC_DISCOVERED_TYPE_ATTACHED) {
+ connected_peer_ = target;
+ CallbackData* cd = new CallbackData(this, 0, "messageread");
+ if (nfc_p2p_set_data_received_cb(connected_peer_,
+ OnP2PDataRecievedCallBack, cd) == NFC_ERROR_NONE)
+ PostSuccess("peerfound");
+ else
+ delete cd;
+ } else {
+ nfc_p2p_unset_data_received_cb(connected_peer_);
+ connected_peer_ = NULL;
+ PostSuccess("peerlost");
+ }
+}
+
+void NfcInstance::OnReadNdef(nfc_error_e result,
+ nfc_ndef_message_h message, CallbackData* cd) {
+ picojson::value retval;
+ if (result == NFC_ERROR_NONE
+ && NdefMessageToJson(message, retval) == NFC_ERROR_NONE)
+ PostResult(cd->event_name_, retval, cd->async_id_);
+ else
+ PostError(cd->async_id_);
+}
+
+void NfcInstance::OnWriteNdef(nfc_error_e result, CallbackData* cd) {
+ if (result == NFC_ERROR_NONE) {
+ PostSuccess(cd->event_name_, cd->async_id_);
+ nfc_ndef_message_destroy(cd->message_);
+ } else {
+ PostError(cd->async_id_);
+ }
+}
+
+void NfcInstance::OnP2PDataRecieved(nfc_p2p_target_h target,
+ nfc_ndef_message_h message, CallbackData* cd) {
+ picojson::value retval;
+ if (target == connected_peer_
+ && NdefMessageToJson(message, retval) == NFC_ERROR_NONE)
+ PostResult(cd->event_name_, retval, cd->async_id_);
+}
+
+void NfcInstance::OnP2PMessageSent(nfc_error_e result, CallbackData* cd) {
+ if (result == NFC_ERROR_NONE) {
+ PostSuccess(cd->event_name_, cd->async_id_);
+ nfc_ndef_message_destroy(cd->message_);
+ } else {
+ PostError(cd->async_id_);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NFC_NFC_INSTANCE_H_
+#define NFC_NFC_INSTANCE_H_
+
+#include <nfc.h>
+#include <string>
+#include "common/extension.h"
+#include "nfc/nfc_callbacks.h"
+
+namespace picojson {
+
+class value;
+
+} // namespace picojson
+
+class NfcInstance : public common::Instance {
+ public:
+ NfcInstance();
+ virtual ~NfcInstance();
+
+ private:
+ // common::Instance implementation.
+ virtual void HandleMessage(const char* msg);
+ virtual void HandleSyncMessage(const char* msg);
+
+ void PollStart(const picojson::value& value);
+ void PollStop(const picojson::value& value);
+ void ReadNdef(const picojson::value& value);
+ void WriteNdef(const picojson::value& value);
+ void SendNdef(const picojson::value& value);
+ void StartHandover(const picojson::value& value);
+ void GetBytes(const picojson::value& value);
+ void GetPayload(const picojson::value& value);
+
+ void SwitchPower(bool state, const picojson::value& value);
+ void PostError(double async_operation_id);
+ void PostSuccess(const std::string& event, double async_operation_id = 0);
+ void PostResult(const std::string& command, double async_operation_id);
+ void PostResult(const std::string& command, const picojson::value& value,
+ double async_operation_id);
+
+ CALLBACK_METHOD(OnActivationChanged, bool, NfcInstance);
+ CALLBACK_METHOD_2(OnTagDiscovered, nfc_discovered_type_e,
+ nfc_tag_h, NfcInstance);
+ CALLBACK_METHOD_2(OnP2PDiscovered, nfc_discovered_type_e,
+ nfc_p2p_target_h, NfcInstance);
+ CALLBACK_METHOD_WITH_DATA(OnPowered, nfc_error_e, NfcInstance);
+ CALLBACK_METHOD_WITH_DATA_2(OnReadNdef, nfc_error_e,
+ nfc_ndef_message_h, NfcInstance);
+ CALLBACK_METHOD_WITH_DATA(OnWriteNdef, nfc_error_e, NfcInstance);
+ CALLBACK_METHOD_WITH_DATA_2(OnP2PDataRecieved, nfc_p2p_target_h,
+ nfc_ndef_message_h, NfcInstance);
+ CALLBACK_METHOD_WITH_DATA(OnP2PMessageSent, nfc_error_e, NfcInstance);
+
+ private:
+ int nfc_manager_init_code_ = 0;
+ bool nfc_manager_activated_ = false;
+ nfc_tag_h attached_tag_ = NULL;
+ nfc_p2p_target_h connected_peer_ = NULL;
+};
+
+#endif // NFC_NFC_INSTANCE_H_
BuildRequires: pkgconfig(capi-appfw-package-manager)
BuildRequires: pkgconfig(capi-network-bluetooth)
BuildRequires: pkgconfig(capi-network-connection)
+BuildRequires: pkgconfig(capi-network-nfc)
BuildRequires: pkgconfig(capi-system-device)
BuildRequires: pkgconfig(capi-system-info)
BuildRequires: pkgconfig(capi-system-power)
'download/download.gyp:*',
'filesystem/filesystem.gyp:*',
'messageport/messageport.gyp:*',
+ 'nfc/nfc.gyp:*',
],
}],
[ 'extension_host_os == "mobile"', {