summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authorarmansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-03 10:37:15 +0000
committerarmansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-03 10:37:15 +0000
commitb763b84f66ae45588718cff2ef53ba0b91b4f66a (patch)
tree6fa077e3240cc045d653ccb28257c6bf97328a22 /device
parent3aeb282799da9acf2f6339e4e2c6461c67a049f7 (diff)
downloadchromium_src-b763b84f66ae45588718cff2ef53ba0b91b4f66a.zip
chromium_src-b763b84f66ae45588718cff2ef53ba0b91b4f66a.tar.gz
chromium_src-b763b84f66ae45588718cff2ef53ba0b91b4f66a.tar.bz2
nfc: Add native NFC API definitions.
Added the headers and non-platform-specific base class definitions for the NFC API. BUG=chromium:316471 TEST=device_unittests Review URL: https://codereview.chromium.org/77563002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238336 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device')
-rw-r--r--device/device_tests.gyp2
-rw-r--r--device/nfc/DEPS5
-rw-r--r--device/nfc/nfc.gyp41
-rw-r--r--device/nfc/nfc_adapter.cc53
-rw-r--r--device/nfc/nfc_adapter.h193
-rw-r--r--device/nfc/nfc_adapter_factory.cc24
-rw-r--r--device/nfc/nfc_adapter_factory.h33
-rw-r--r--device/nfc/nfc_ndef_record.cc213
-rw-r--r--device/nfc/nfc_ndef_record.h161
-rw-r--r--device/nfc/nfc_ndef_record_unittest.cc238
-rw-r--r--device/nfc/nfc_peer.cc15
-rw-r--r--device/nfc/nfc_peer.h92
-rw-r--r--device/nfc/nfc_tag.cc15
-rw-r--r--device/nfc/nfc_tag.h93
-rw-r--r--device/nfc/nfc_tag_technology.cc39
-rw-r--r--device/nfc/nfc_tag_technology.h100
16 files changed, 1317 insertions, 0 deletions
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index c9d29d44..00bd47b 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -17,6 +17,7 @@
'../testing/gtest.gyp:gtest',
'bluetooth/bluetooth.gyp:device_bluetooth',
'bluetooth/bluetooth.gyp:device_bluetooth_mocks',
+ 'nfc/nfc.gyp:device_nfc',
'usb/usb.gyp:device_usb',
],
'sources': [
@@ -29,6 +30,7 @@
'bluetooth/bluetooth_service_record_win_unittest.cc',
'bluetooth/bluetooth_task_manager_win_unittest.cc',
'bluetooth/bluetooth_utils_unittest.cc',
+ 'nfc/nfc_ndef_record_unittest.cc',
'usb/usb_ids_unittest.cc',
],
'conditions': [
diff --git a/device/nfc/DEPS b/device/nfc/DEPS
new file mode 100644
index 0000000..428dccf
--- /dev/null
+++ b/device/nfc/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+chromeos/dbus",
+ "+dbus",
+ "+third_party/cros_system_api/dbus",
+]
diff --git a/device/nfc/nfc.gyp b/device/nfc/nfc.gyp
new file mode 100644
index 0000000..eafa31d
--- /dev/null
+++ b/device/nfc/nfc.gyp
@@ -0,0 +1,41 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'device_nfc',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ ],
+ 'sources': [
+ 'nfc_adapter.cc',
+ 'nfc_adapter.h',
+ 'nfc_adapter_factory.cc',
+ 'nfc_adapter_factory.h',
+ 'nfc_ndef_record.cc',
+ 'nfc_ndef_record.h',
+ 'nfc_peer.cc',
+ 'nfc_peer.h',
+ 'nfc_tag.cc',
+ 'nfc_tag.h',
+ 'nfc_tag_technology.cc',
+ 'nfc_tag_technology.h'
+ ],
+ 'conditions': [
+ ['chromeos==1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:dbus',
+ '../../chromeos/chromeos.gyp:chromeos',
+ '../../dbus/dbus.gyp:dbus',
+ ]
+ }],
+ ],
+ },
+ ],
+}
diff --git a/device/nfc/nfc_adapter.cc b/device/nfc/nfc_adapter.cc
new file mode 100644
index 0000000..dd790b2
--- /dev/null
+++ b/device/nfc/nfc_adapter.cc
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/nfc/nfc_adapter.h"
+
+#include "base/lazy_instance.h"
+#include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
+#include "device/nfc/nfc_peer.h"
+#include "device/nfc/nfc_tag.h"
+
+namespace device {
+
+NfcAdapter::NfcAdapter() {
+}
+
+NfcAdapter::~NfcAdapter() {
+ STLDeleteValues(&peers_);
+ STLDeleteValues(&tags_);
+}
+
+void NfcAdapter::GetPeers(PeerList* peer_list) const {
+ peer_list->clear();
+ for (PeersMap::const_iterator iter = peers_.begin();
+ iter != peers_.end(); ++iter) {
+ peer_list->push_back(iter->second);
+ }
+}
+
+void NfcAdapter::GetTags(TagList* tag_list) const {
+ tag_list->clear();
+ for (TagsMap::const_iterator iter = tags_.begin();
+ iter != tags_.end(); ++iter) {
+ tag_list->push_back(iter->second);
+ }
+}
+
+NfcPeer* NfcAdapter::GetPeer(const std::string& identifier) const {
+ PeersMap::const_iterator iter = peers_.find(identifier);
+ if (iter != peers_.end())
+ return iter->second;
+ return NULL;
+}
+
+NfcTag* NfcAdapter::GetTag(const std::string& identifier) const {
+ TagsMap::const_iterator iter = tags_.find(identifier);
+ if (iter != tags_.end())
+ return iter->second;
+ return NULL;
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_adapter.h b/device/nfc/nfc_adapter.h
new file mode 100644
index 0000000..373f4cc
--- /dev/null
+++ b/device/nfc/nfc_adapter.h
@@ -0,0 +1,193 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_NFC_NFC_ADAPTER_H_
+#define DEVICE_NFC_NFC_ADAPTER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+
+namespace device {
+
+class NfcPeer;
+class NfcTag;
+
+// NfcAdapter represents a local NFC adapter which may be used to interact with
+// NFC tags and remote NFC adapters on platforms that support NFC. Through
+// instances of this class, users can obtain important information such as if
+// and/or when an adapter is present, supported NFC technologies, and the
+// adapter's power and polling state. NfcAdapter instances can be used to power
+// up/down the NFC adapter and its Observer interface allows users to get
+// notified when new adapters are added/removed and when remote NFC tags and
+// devices were detected or lost.
+//
+// A system can contain more than one NFC adapter (e.g. external USB adapters)
+// but Chrome will have only one NfcAdapter instance. This instance will do
+// its best to represent all underlying adapters but will only allow
+// interacting with only one at a given time. If the currently represented
+// adapter is removed from the system, the NfcAdapter instance will update to
+// reflect the information from the next available adapter.
+class NfcAdapter : public base::RefCounted<NfcAdapter> {
+ public:
+ // Interface for observing changes from NFC adapters.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // Called when the presence of the adapter |adapter| changes. When |present|
+ // is true, this indicates that the adapter has now become present, while a
+ // value of false indicates that the adapter is no longer available on the
+ // current system.
+ virtual void AdapterPresentChanged(NfcAdapter* adapter, bool present) {}
+
+ // Called when the radio power state of the adapter |adapter| changes. If
+ // |powered| is true, the adapter radio is turned on, otherwise it's turned
+ // off.
+ virtual void AdapterPoweredChanged(NfcAdapter* adapter, bool powered) {}
+
+ // Called when the "polling" state of the adapter |adapter| changes. If
+ // |polling| is true, the adapter is currently polling for remote tags and
+ // devices. If false, the adapter isn't polling, either because a poll loop
+ // was never started or because a connection with a tag or peer has been
+ // established.
+ virtual void AdapterPollingChanged(NfcAdapter* adapter, bool polling) {}
+
+ // Called when an NFC tag |tag| has been found by the adapter |adapter|.
+ // The observer can use this method to take further action on the tag object
+ // |tag|, such as reading its records or writing to it. While |tag| will be
+ // valid within the context of this call, its life-time cannot be guaranteed
+ // once this call returns, as the object may get destroyed if the connection
+ // with the tag is lost. Instead of caching the pointer directly, observers
+ // should store the tag's assigned unique identifier instead, which can be
+ // used to obtain a pointer to the tag, as long as it exists.
+ virtual void TagFound(NfcAdapter* adapter, NfcTag* tag) {}
+
+ // Called when the NFC tag |tag| is no longer known by the adapter
+ // |adapter|. |tag| should not be cached.
+ virtual void TagLost(NfcAdapter* adapter, NfcTag* tag) {}
+
+ // Called when a remote NFC adapter |peer| has been detected, which is
+ // available for peer-to-peer communication over NFC. The observer can use
+ // this method to take further action on |peer| such as reading its records
+ // or pushing NDEFs to it. While |peer| will be valid within the context of
+ // this call, its life-time cannot be guaranteed once this call returns, as
+ // the object may get destroyed if the connection with the peer is lost.
+ // Instead of caching the pointer directly, observers should store the
+ // peer's assigned unique identifier instead, which can be used to obtain a
+ // pointer to the peer, as long as it exists.
+ virtual void PeerFound(NfcAdapter* adaper, NfcPeer* peer) {}
+
+ // Called when the remote NFC adapter |peer| is no longer known by the
+ // adapter |adapter|. |peer| should not be cached.
+ virtual void PeerLost(NfcAdapter* adapter, NfcPeer* peer) {}
+ };
+
+ // The ErrorCallback is used by methods to asynchronously report errors.
+ typedef base::Closure ErrorCallback;
+
+ // Typedefs for lists of NFC peer and NFC tag objects.
+ typedef std::vector<NfcPeer*> PeerList;
+ typedef std::vector<NfcTag*> TagList;
+
+ // Adds and removes observers for events on this NFC adapter. If monitoring
+ // multiple adapters, check the |adapter| parameter of observer methods to
+ // determine which adapter is issuing the event.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Indicates whether an underlying adapter is actually present on the
+ // system. An adapter that was previously present can become no longer
+ // present, for example, if all physical adapters that can back it up were
+ // removed from the system.
+ virtual bool IsPresent() const = 0;
+
+ // Indicates whether the adapter radio is powered.
+ virtual bool IsPowered() const = 0;
+
+ // Indicates whether the adapter is polling for remote NFC tags and peers.
+ virtual bool IsPolling() const = 0;
+
+ // Indicates whether the NfcAdapter instance is initialized and ready to use.
+ virtual bool IsInitialized() const = 0;
+
+ // Requests a change to the adapter radio power. Setting |powered| to true
+ // will turn on the radio and false will turn it off. On success, |callback|
+ // will be invoked. On failure, |error_callback| will be invoked, which can
+ // happen if the radio power is already in the requested state, or if the
+ // underlying adapter is not present.
+ virtual void SetPowered(bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Requests the adapter to begin its poll loop to start looking for remote
+ // NFC tags and peers. On success, |callback| will be invoked. On failure,
+ // |error_callback| will be invoked. This method can fail for various
+ // reasons, including:
+ // - The adapter radio is not powered.
+ // - The adapter is already polling.
+ // - The adapter is busy; it has already established a connection to a
+ // remote tag or peer.
+ // Bear in mind that this method may be called by multiple users of the same
+ // adapter.
+ virtual void StartPolling(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Requests the adapter to stop its current poll loop. On success, |callback|
+ // will be invoked. On failure, |error_callback| will be invoked. This method
+ // can fail if the adapter is not polling when this method was called. Bear
+ // in mind that this method may be called by multiple users of the same
+ // adapter and polling may not actually stop if other callers have called
+ // StartPolling() in the mean time.
+ virtual void StopPolling(const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Returns a list containing all known peers in |peer_list|. If |peer_list|
+ // was non-empty at the time of the call, it will be cleared. The contents of
+ // |peer_list| at the end of this call are owned by the adapter.
+ virtual void GetPeers(PeerList* peer_list) const;
+
+ // Returns a list containing all known tags in |tag_list|. If |tag_list| was
+ // non-empty at the time of the call, it will be cleared. The contents of
+ // |tag_list| at the end of this call are owned by the adapter.
+ virtual void GetTags(TagList* tag_list) const;
+
+ // Returns a pointer to the peer with the given identifier |identifier| or
+ // NULL if no such peer is known. If a non-NULL pointer is returned, the
+ // instance that it points to is owned by this adapter.
+ virtual NfcPeer* GetPeer(const std::string& identifier) const;
+
+ // Returns a pointer to the tag with the given identifier |identifier| or
+ // NULL if no such tag is known. If a non-NULL pointer is returned, the
+ // instance that it points to is owned by this adapter.
+ virtual NfcTag* GetTag(const std::string& identifier) const;
+
+ protected:
+ friend class base::RefCounted<NfcAdapter>;
+
+ // The default constructor does nothing. The destructor deletes all known
+ // NfcPeer and NfcTag instances.
+ NfcAdapter();
+ virtual ~NfcAdapter();
+
+ // Peers and tags that have been found. The key is the unique identifier
+ // assigned to the peer or tag and the value is a pointer to the
+ // corresponding NfcPeer or NfcTag object, whose lifetime is managed by the
+ // adapter instance.
+ typedef std::map<const std::string, NfcPeer*> PeersMap;
+ typedef std::map<const std::string, NfcTag*> TagsMap;
+
+ PeersMap peers_;
+ TagsMap tags_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NfcAdapter);
+};
+
+} // namespace device
+
+#endif // DEVICE_NFC_NFC_ADAPTER_H_
diff --git a/device/nfc/nfc_adapter_factory.cc b/device/nfc/nfc_adapter_factory.cc
new file mode 100644
index 0000000..c05c933
--- /dev/null
+++ b/device/nfc/nfc_adapter_factory.cc
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/nfc/nfc_adapter_factory.h"
+
+#include "base/lazy_instance.h"
+#include "base/memory/weak_ptr.h"
+
+namespace device {
+
+// static
+bool NfcAdapterFactory::IsNfcAvailable() {
+ // TODO(armansito): Return true on supported platforms here.
+ return false;
+}
+
+// static
+void NfcAdapterFactory::GetAdapter(const AdapterCallback& /* callback */) {
+ // TODO(armansito): Create platform-specific implementation instances here.
+ // No platform currently supports NFC, so we never invoke the callback.
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_adapter_factory.h b/device/nfc/nfc_adapter_factory.h
new file mode 100644
index 0000000..b813f91
--- /dev/null
+++ b/device/nfc/nfc_adapter_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_NFC_NFC_ADAPTER_FACTORY_H_
+#define DEVICE_NFC_NFC_ADAPTER_FACTORY_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "device/nfc/nfc_adapter.h"
+
+namespace device {
+
+// NfcAdapterFactory is a class that contains static methods, which
+// instantiate either a specific NFC adapter, or the generic "default
+// adapter" which may change depending on availability.
+class NfcAdapterFactory {
+ public:
+ typedef base::Callback<void(scoped_refptr<NfcAdapter>)> AdapterCallback;
+
+ // Returns true if NFC is available for the current platform.
+ static bool IsNfcAvailable();
+
+ // Returns the shared instance of the default adapter, creating and
+ // initializing it if necessary. |callback| is called with the adapter
+ // instance passed only once the adapter is fully initialized and ready to
+ // use.
+ static void GetAdapter(const AdapterCallback& callback);
+};
+
+} // namespace device
+
+#endif // DEVICE_NFC_NFC_ADAPTER_FACTORY_H_
diff --git a/device/nfc/nfc_ndef_record.cc b/device/nfc/nfc_ndef_record.cc
new file mode 100644
index 0000000..ec13c2f
--- /dev/null
+++ b/device/nfc/nfc_ndef_record.cc
@@ -0,0 +1,213 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/nfc/nfc_ndef_record.h"
+
+#include <map>
+
+#include "base/logging.h"
+
+using base::DictionaryValue;
+using base::ListValue;
+
+namespace device {
+
+namespace {
+
+typedef std::map<std::string, base::Value::Type> FieldValueMap;
+
+bool CheckFieldsAreValid(
+ const FieldValueMap& required_fields,
+ const FieldValueMap& optional_fields,
+ const DictionaryValue* data) {
+ size_t required_count = 0;
+ for (DictionaryValue::Iterator iter(*data);
+ !iter.IsAtEnd(); iter.Advance()) {
+ FieldValueMap::const_iterator field_iter =
+ required_fields.find(iter.key());
+ if (field_iter == required_fields.end()) {
+ // Field wasn't one of the required fields. Check if optional.
+ field_iter = optional_fields.find(iter.key());
+
+ if (field_iter == optional_fields.end()) {
+ // If the field isn't one of the optional fields either, then it's
+ // invalid.
+ VLOG(1) << "Tried to populate record with invalid field: "
+ << iter.key();
+ return false;
+ }
+ } else {
+ required_count++;
+ }
+ // The field is invalid, if the type of its value is incorrect.
+ if (field_iter->second != iter.value().GetType()) {
+ VLOG(1) << "Provided value for field \"" << iter.key() << "\" has type "
+ << iter.value().GetType() << ", expected: "
+ << field_iter->second;
+ return false;
+ }
+ }
+ // Check for required fields.
+ if (required_count != required_fields.size()) {
+ VLOG(1) << "Provided data did not contain all required fields for "
+ << "requested NDEF type.";
+ return false;
+ }
+ return true;
+}
+
+// Verifies that the contents of |data| conform to the fields of NDEF type
+// "Text".
+bool HandleTypeText(const DictionaryValue* data) {
+ VLOG(1) << "Populating record with type \"Text\".";
+ FieldValueMap required_fields;
+ required_fields[NfcNdefRecord::kFieldText] = base::Value::TYPE_STRING;
+ FieldValueMap optional_fields;
+ optional_fields[NfcNdefRecord::kFieldEncoding] = base::Value::TYPE_STRING;
+ optional_fields[NfcNdefRecord::kFieldLanguageCode] = base::Value::TYPE_STRING;
+ if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
+ VLOG(1) << "Failed to populate record.";
+ return false;
+ }
+ return true;
+}
+
+// Verifies that the contents of |data| conform to the fields of NDEF type
+// "SmartPoster".
+bool HandleTypeSmartPoster(const DictionaryValue* data) {
+ VLOG(1) << "Populating record with type \"SmartPoster\".";
+ FieldValueMap required_fields;
+ required_fields[NfcNdefRecord::kFieldURI] = base::Value::TYPE_STRING;
+ FieldValueMap optional_fields;
+ optional_fields[NfcNdefRecord::kFieldAction] = base::Value::TYPE_STRING;
+ optional_fields[NfcNdefRecord::kFieldMimeType] = base::Value::TYPE_STRING;
+ // base::Value restricts the number types to BOOL, INTEGER, and DOUBLE only.
+ // uint32 will automatically get converted to a double. "target size" is
+ // really a uint32 but we define it as a double for this reason.
+ // (See dbus/values_util.h).
+ optional_fields[NfcNdefRecord::kFieldTargetSize] = base::Value::TYPE_DOUBLE;
+ optional_fields[NfcNdefRecord::kFieldTitles] = base::Value::TYPE_LIST;
+ if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
+ VLOG(1) << "Failed to populate record.";
+ return false;
+ }
+ // Verify that the "titles" field was formatted correctly, if it exists.
+ const ListValue* titles = NULL;
+ if (data->GetList(NfcNdefRecord::kFieldTitles, &titles)) {
+ if (titles->empty()) {
+ VLOG(1) << "\"titles\" field of SmartPoster is empty.";
+ return false;
+ }
+ for (ListValue::const_iterator iter = titles->begin();
+ iter != titles->end(); ++iter) {
+ const DictionaryValue* title_data = NULL;
+ if (!(*iter)->GetAsDictionary(&title_data)) {
+ VLOG(1) << "\"title\" entry for SmartPoster contains an invalid value "
+ << "type";
+ return false;
+ }
+ if (!HandleTypeText(title_data)) {
+ VLOG(1) << "Badly formatted \"title\" entry for SmartPoster.";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// Verifies that the contents of |data| conform to the fields of NDEF type
+// "URI".
+bool HandleTypeUri(const DictionaryValue* data) {
+ VLOG(1) << "Populating record with type \"URI\".";
+ FieldValueMap required_fields;
+ required_fields[NfcNdefRecord::kFieldURI] = base::Value::TYPE_STRING;
+ FieldValueMap optional_fields;
+ optional_fields[NfcNdefRecord::kFieldMimeType] = base::Value::TYPE_STRING;
+ optional_fields[NfcNdefRecord::kFieldTargetSize] = base::Value::TYPE_DOUBLE;
+ if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
+ VLOG(1) << "Failed to populate record.";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+const char NfcNdefRecord::kFieldEncoding[] = "encoding";
+// static
+const char NfcNdefRecord::kFieldLanguageCode[] = "languageCode";
+// static
+const char NfcNdefRecord::kFieldText[] = "text";
+// static
+const char NfcNdefRecord::kFieldURI[] = "uri";
+// static
+const char NfcNdefRecord::kFieldMimeType[] = "mimeType";
+// static
+const char NfcNdefRecord::kFieldTargetSize[] = "targetSize";
+// static
+const char NfcNdefRecord::kFieldTitles[] = "titles";
+// static
+const char NfcNdefRecord::kFieldAction[] = "action";
+// static
+const char NfcNdefRecord::kEncodingUtf8[] = "UTF-8";
+// static
+const char NfcNdefRecord::kEncodingUtf16[] = "UTF-16";
+// static
+const char NfcNdefRecord::kSmartPosterActionDo[] = "do";
+// static
+const char NfcNdefRecord::kSmartPosterActionSave[] = "save";
+// static
+const char NfcNdefRecord::kSmartPosterActionOpen[] = "open";
+
+NfcNdefRecord::NfcNdefRecord() : type_(kTypeUnknown) {
+}
+
+NfcNdefRecord::~NfcNdefRecord() {
+}
+
+bool NfcNdefRecord::IsPopulated() const {
+ return type_ != kTypeUnknown;
+}
+
+bool NfcNdefRecord::Populate(Type type, const DictionaryValue* data) {
+ if (IsPopulated())
+ return false;
+
+ DCHECK(data_.empty());
+
+ // At this time, only "Text", "URI", and "SmartPoster" are supported.
+ bool result = false;
+ switch (type) {
+ case kTypeText:
+ result = HandleTypeText(data);
+ break;
+ case kTypeSmartPoster:
+ result = HandleTypeSmartPoster(data);
+ break;
+ case kTypeURI:
+ result = HandleTypeUri(data);
+ break;
+ default:
+ VLOG(1) << "Unsupported NDEF type: " << type;
+ break;
+ }
+ if (!result)
+ return false;
+ type_ = type;
+ data_.MergeDictionary(data);
+ return true;
+}
+
+NfcNdefMessage::NfcNdefMessage() {
+}
+
+NfcNdefMessage::~NfcNdefMessage() {
+}
+
+void NfcNdefMessage::AddRecord(NfcNdefRecord* record) {
+ records_.push_back(record);
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_ndef_record.h b/device/nfc/nfc_ndef_record.h
new file mode 100644
index 0000000..2be66b1
--- /dev/null
+++ b/device/nfc/nfc_ndef_record.h
@@ -0,0 +1,161 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_NFC_NFC_NDEF_RECORD_H_
+#define DEVICE_NFC_NFC_NDEF_RECORD_H_
+
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+
+namespace device {
+
+// NfcNdefRecord represents an NDEF (NFC Data Exchange Format) record. NDEF is
+// a light-weight binary format specified by the NFC Forum for transmission and
+// storage of typed data over NFC. NDEF defines two constructs: NDEF records and
+// messages. An NDEF record contains typed data, such as MIME-type media, a URI,
+// or a custom application payload, whereas an NDEF message is a container for
+// one or more NDEF records.
+class NfcNdefRecord {
+ public:
+ // NDEF record types that define the payload of the NDEF record.
+ enum Type {
+ kTypeHandoverCarrier,
+ kTypeHandoverRequest,
+ kTypeHandoverSelect,
+ kTypeSmartPoster,
+ kTypeText,
+ kTypeURI,
+ kTypeUnknown
+ };
+
+ // The following are strings that define a possible field of an NDEF record.
+ // These strings are used as the keys in the dictionary returned by |data|.
+ // Not all fields are always present in an NDEF record, where the presence
+ // of a field depends on the type of the record. While some fields are
+ // required for a specific record type, others can be optional and won't
+ // always be present.
+
+ // Fields for type "Text".
+
+ // The character encoding. When present, the value is one of |kEncodingUtf8|
+ // and |kEncodingUtf16|. Otherwise, this field is optional.
+ static const char kFieldEncoding[];
+
+ // The ISO/IANA language code (e.g. "en" or "jp"). This field is optional.
+ static const char kFieldLanguageCode[];
+
+ // The human readable representation of a text. This field is mandatory.
+ static const char kFieldText[];
+
+ // Fields for type "URI".
+
+ // The complete URI, including the scheme and the resource. This field is
+ // required.
+ static const char kFieldURI[];
+
+ // The URI object MIME type. This is a description of the MIME type of the
+ // object the URI points at. This field is optional.
+ static const char kFieldMimeType[];
+
+ // The size of the object the URI points at. This field is optional.
+ // If present, the value is an unsigned integer. Since base/values.h does not
+ // define an unsigned integer type, use a base::DoubleValue to store this.
+ static const char kFieldTargetSize[];
+
+ // Fields for type "SmartPoster". A SmartPoster can contain all possible
+ // fields of a "URI" record, in addition to the following:
+
+ // The "title" of the SmartPoster. This is an optional field. If present, the
+ // value of this field is a list of dictionaries, where each dictionary
+ // contains the possible fields of a "Text" record. If the list contains
+ // more than one element, each element usually represents the same "title"
+ // text in a different language.
+ static const char kFieldTitles[];
+
+ // The suggested course of action. The value of this field is one of
+ // |kSmartPosterAction*|. This field is optional.
+ static const char kFieldAction[];
+
+ // Possible values for character encoding.
+ static const char kEncodingUtf8[];
+ static const char kEncodingUtf16[];
+
+ // Possible actions defined by the NFC forum SmartPoster record type. Each
+ // action is a suggestion to the application indicating the action it should
+ // take with the contents of the record.
+
+ // Do the action. e.g. open a URI, send an SMS, dial a phone number.
+ static const char kSmartPosterActionDo[];
+
+ // Store data, e.g. store an SMS, bookmark a URI, etc.
+ static const char kSmartPosterActionSave[];
+
+ // Open the data for editing.
+ static const char kSmartPosterActionOpen[];
+
+ NfcNdefRecord();
+ virtual ~NfcNdefRecord();
+
+ // Returns the type that defines the payload of this NDEF record.
+ Type type() const { return type_; }
+
+ // Returns the contents of this record in the form of a mapping from keys
+ // declared above to their stored values.
+ const base::DictionaryValue& data() const { return data_; }
+
+ // Returns true, if this record has been populated via a call to "Populate".
+ bool IsPopulated() const;
+
+ // Populates the record with the contents of |data| and sets its type to
+ // |type|. Returns true, if the record was successfully populated. If a
+ // failure occurs, e.g. |data| contains values that are not allowed in
+ // records of type |type| or if |data| does not contain mandatory fields of
+ // |type|, this method returns false. Populating an instance of an
+ // NfcNdefRecord is allowed only once and after a successful call to this
+ // method, all subsequent calls to this method will fail. Use IsPopulated()
+ // to determine if this record can be populated.
+ bool Populate(Type type, const base::DictionaryValue* data);
+
+ private:
+ // The type of this record.
+ Type type_;
+
+ // The contents of the record.
+ base::DictionaryValue data_;
+
+ DISALLOW_COPY_AND_ASSIGN(NfcNdefRecord);
+};
+
+// NfcNdefMessage represent an NDEF message. An NDEF message, contains one or
+// more NDEF records and the order in which the records are stored dictates the
+// order in which applications are meant to interpret them. For example, a
+// client may decide to dispatch to applications based on the first record in
+// the sequence.
+class NfcNdefMessage {
+ public:
+ // Typedef for a list of NDEF records.
+ typedef std::vector<NfcNdefRecord*> RecordList;
+
+ NfcNdefMessage();
+ virtual ~NfcNdefMessage();
+
+ // The NDEF records that are contained in this message.
+ const RecordList& records() const { return records_; }
+
+ // Adds the NDEF record |record| to the sequence of records that this
+ // NdefMessage contains.
+ void AddRecord(NfcNdefRecord* record);
+
+ private:
+ // The NDEF records that are contained by this message.
+ RecordList records_;
+
+ DISALLOW_COPY_AND_ASSIGN(NfcNdefMessage);
+};
+
+} // namespace device
+
+#endif // DEVICE_NFC_NFC_NDEF_RECORD_H_
diff --git a/device/nfc/nfc_ndef_record_unittest.cc b/device/nfc/nfc_ndef_record_unittest.cc
new file mode 100644
index 0000000..00c2d2f5
--- /dev/null
+++ b/device/nfc/nfc_ndef_record_unittest.cc
@@ -0,0 +1,238 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "device/nfc/nfc_ndef_record.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::DictionaryValue;
+using base::ListValue;
+using base::StringValue;
+
+namespace device {
+
+namespace {
+
+const char kTestAction[] = "test-action";
+const char kTestEncoding[] = "test-encoding";
+const char kTestLanguageCode[] = "test-language-code";
+const char kTestMimeType[] = "test-mime-type";
+const uint32 kTestTargetSize = 0;
+const char kTestText[] = "test-text";
+const char kTestURI[] = "test-uri";
+
+} // namespace
+
+TEST(NfcNdefRecordTest, PopulateTextRecord) {
+ DictionaryValue data;
+ scoped_ptr<NfcNdefRecord> record(new NfcNdefRecord());
+
+ // Missing text field. Should fail.
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeText, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Text field with incorrect entry. Should fail.
+ data.SetInteger(NfcNdefRecord::kFieldText, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeText, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Text field with correct entry. Should succeed.
+ data.SetString(NfcNdefRecord::kFieldText, kTestText);
+ EXPECT_TRUE(record->Populate(NfcNdefRecord::kTypeText, &data));
+ EXPECT_TRUE(record->IsPopulated());
+ EXPECT_EQ(NfcNdefRecord::kTypeText, record->type());
+
+ // Populating a successfully populated record should fail.
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeText, &data));
+
+ // Recycle the record.
+ record.reset(new NfcNdefRecord());
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Incorrect optional fields. Should fail.
+ data.SetInteger(NfcNdefRecord::kFieldLanguageCode, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeText, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ data.SetString(NfcNdefRecord::kFieldLanguageCode, kTestLanguageCode);
+ data.SetInteger(NfcNdefRecord::kFieldEncoding, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeText, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Optional fields are correct. Should succeed.
+ data.SetString(NfcNdefRecord::kFieldEncoding, kTestEncoding);
+ EXPECT_TRUE(record->Populate(NfcNdefRecord::kTypeText, &data));
+ EXPECT_TRUE(record->IsPopulated());
+ EXPECT_EQ(NfcNdefRecord::kTypeText, record->type());
+
+ // Compare record contents.
+ std::string string_value;
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldText, &string_value));
+ EXPECT_EQ(kTestText, string_value);
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldLanguageCode, &string_value));
+ EXPECT_EQ(kTestLanguageCode, string_value);
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldEncoding, &string_value));
+ EXPECT_EQ(kTestEncoding, string_value);
+}
+
+TEST(NfcNdefRecordTest, PopulateUriRecord) {
+ DictionaryValue data;
+ scoped_ptr<NfcNdefRecord> record(new NfcNdefRecord());
+
+ // Missing URI field. Should fail.
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // URI field with incorrect entry. Should fail.
+ data.SetInteger(NfcNdefRecord::kFieldURI, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // URI field with correct entry. Should succeed.
+ data.SetString(NfcNdefRecord::kFieldURI, kTestURI);
+ EXPECT_TRUE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+ EXPECT_TRUE(record->IsPopulated());
+ EXPECT_EQ(NfcNdefRecord::kTypeURI, record->type());
+
+ // Populating a successfully populated record should fail.
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+
+ // Recycle the record.
+ record.reset(new NfcNdefRecord());
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Incorrect optional fields. Should fail.
+ data.SetInteger(NfcNdefRecord::kFieldMimeType, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ data.SetString(NfcNdefRecord::kFieldMimeType, kTestMimeType);
+ data.SetInteger(NfcNdefRecord::kFieldTargetSize, kTestTargetSize);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Optional fields are correct. Should succeed.
+ data.SetDouble(NfcNdefRecord::kFieldTargetSize,
+ static_cast<double>(kTestTargetSize));
+ EXPECT_TRUE(record->Populate(NfcNdefRecord::kTypeURI, &data));
+ EXPECT_TRUE(record->IsPopulated());
+ EXPECT_EQ(NfcNdefRecord::kTypeURI, record->type());
+
+ // Compare record contents.
+ std::string string_value;
+ double double_value;
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldURI, &string_value));
+ EXPECT_EQ(kTestURI, string_value);
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldMimeType, &string_value));
+ EXPECT_EQ(kTestMimeType, string_value);
+ EXPECT_TRUE(record->data().GetDouble(
+ NfcNdefRecord::kFieldTargetSize, &double_value));
+ EXPECT_EQ(kTestTargetSize, static_cast<uint32>(double_value));
+}
+
+TEST(NfcNdefRecordTest, PopulateSmartPoster) {
+ DictionaryValue data;
+ scoped_ptr<NfcNdefRecord> record(new NfcNdefRecord());
+
+ // Missing URI field. Should fail.
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // URI field with incorrect entry. Should fail.
+ data.SetInteger(NfcNdefRecord::kFieldURI, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // URI field with correct entry. Should succeed.
+ data.SetString(NfcNdefRecord::kFieldURI, kTestURI);
+ EXPECT_TRUE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_TRUE(record->IsPopulated());
+ EXPECT_EQ(NfcNdefRecord::kTypeSmartPoster, record->type());
+
+ // Populating a successfully populated record should fail.
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+
+ // Recycle the record.
+ record.reset(new NfcNdefRecord());
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Incorrect optional fields. Should fail.
+ data.SetInteger(NfcNdefRecord::kFieldAction, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ data.SetString(NfcNdefRecord::kFieldAction, kTestAction);
+ data.SetInteger(NfcNdefRecord::kFieldMimeType, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ data.SetString(NfcNdefRecord::kFieldMimeType, kTestMimeType);
+ data.SetInteger(NfcNdefRecord::kFieldTargetSize, kTestTargetSize);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ data.SetDouble(NfcNdefRecord::kFieldTargetSize, kTestTargetSize);
+ data.SetInteger(NfcNdefRecord::kFieldTitles, 0);
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Empty titles value should fail.
+ ListValue* list_value = new ListValue();
+ data.Set(NfcNdefRecord::kFieldTitles, list_value);
+
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Title value with missing required field.
+ DictionaryValue* title_value = new DictionaryValue();
+ list_value->Append(title_value);
+
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Title value with invalid "text" field.
+ title_value->SetInteger(NfcNdefRecord::kFieldText, 0);
+
+ EXPECT_FALSE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_FALSE(record->IsPopulated());
+
+ // Title value with valid "text" field.
+ title_value->SetString(NfcNdefRecord::kFieldText, kTestText);
+
+ EXPECT_TRUE(record->Populate(NfcNdefRecord::kTypeSmartPoster, &data));
+ EXPECT_TRUE(record->IsPopulated());
+
+ // Verify the record contents.
+ std::string string_value;
+ double double_value;
+ const ListValue* const_list_value;
+ const DictionaryValue* const_dictionary_value;
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldURI, &string_value));
+ EXPECT_EQ(kTestURI, string_value);
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldMimeType, &string_value));
+ EXPECT_EQ(kTestMimeType, string_value);
+ EXPECT_TRUE(record->data().GetDouble(
+ NfcNdefRecord::kFieldTargetSize, &double_value));
+ EXPECT_EQ(kTestTargetSize, static_cast<uint32>(double_value));
+ EXPECT_TRUE(record->data().GetString(
+ NfcNdefRecord::kFieldAction, &string_value));
+ EXPECT_EQ(kTestAction, string_value);
+ EXPECT_TRUE(record->data().GetList(
+ NfcNdefRecord::kFieldTitles, &const_list_value));
+ EXPECT_EQ(static_cast<size_t>(1), const_list_value->GetSize());
+ EXPECT_TRUE(const_list_value->GetDictionary(0, &const_dictionary_value));
+ EXPECT_TRUE(const_dictionary_value->GetString(
+ NfcNdefRecord::kFieldText, &string_value));
+ EXPECT_EQ(kTestText, string_value);
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_peer.cc b/device/nfc/nfc_peer.cc
new file mode 100644
index 0000000..dc2fb2f
--- /dev/null
+++ b/device/nfc/nfc_peer.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/nfc/nfc_peer.h"
+
+namespace device {
+
+NfcPeer::NfcPeer() {
+}
+
+NfcPeer::~NfcPeer() {
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_peer.h b/device/nfc/nfc_peer.h
new file mode 100644
index 0000000..1578738
--- /dev/null
+++ b/device/nfc/nfc_peer.h
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_NFC_NFC_PEER_H_
+#define DEVICE_NFC_NFC_PEER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "device/nfc/nfc_ndef_record.h"
+
+namespace device {
+
+// NfcPeer represents a remote NFC adapter that is available for P2P
+// communication with the local adapter. Instances of NfcPeer allow two
+// kinds of P2P interaction that is supported by NFC:
+//
+// - NDEF. Specifically, reading NDEF records found on the peer device and
+// pushing NDEF records to it (e.g. via SNEP or Android Beam), in the form
+// of an NDEF message as specified by the NFC forum.
+// - Initiating a handover. On platforms that support it, handover can be
+// used to quickly bootstrap a Bluetooth or WiFi based connection between
+// the two devices over NFC.
+class NfcPeer {
+ public:
+ // NFC handover types.
+ enum HandoverType {
+ kHandoverTypeBluetooth,
+ kHandoverTypeWiFi
+ };
+
+ // Interface for observing changes from NFC peer devices.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // This method will be called when an NDEF message |message| from the peer
+ // device |peer| is received. Users can use this method to be notified of
+ // new records on the device and when the initial set of records are
+ // received from it, if any.
+ virtual void RecordsReceived(NfcPeer* peer,
+ const NfcNdefMessage& message) {}
+ };
+
+ // The ErrorCallback is used by methods to asynchronously report errors.
+ typedef base::Closure ErrorCallback;
+
+ virtual ~NfcPeer();
+
+ // Adds and removes observers for events on this NFC peer. If monitoring
+ // multiple peers, check the |peer| parameter of observer methods to
+ // determine which peer is issuing the event.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Returns the unique identifier assigned to this peer.
+ virtual std::string GetIdentifier() const = 0;
+
+ // Returns all NDEF records that were received from the peer device in the
+ // form of a NDEF message. If the returned NDEF message contains no records,
+ // this only means that no records have yet been received from the device.
+ // Users should use this method in conjunction with the Observer methods
+ // to be notified when the records are ready.
+ virtual NfcNdefMessage GetNdefMessage() const = 0;
+
+ // Sends the NDEF records contained in |message| to the peer device. On
+ // success, |callback| will be invoked. On failure, |error_callback| will be
+ // invoked.
+ virtual void PushNdef(NfcNdefMessage* message,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Initiates WiFi or Bluetooth pairing with the NFC peer device based on
+ // |handover_type|. On success, |callback| will be invoked. On failure,
+ // |error_callback| will be invoked.
+ virtual void StartHandover(HandoverType handover_type,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ protected:
+ NfcPeer();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NfcPeer);
+};
+
+} // namespace device
+
+#endif // DEVICE_NFC_NFC_PEER_H_
diff --git a/device/nfc/nfc_tag.cc b/device/nfc/nfc_tag.cc
new file mode 100644
index 0000000..9b58bfc
--- /dev/null
+++ b/device/nfc/nfc_tag.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/nfc/nfc_tag.h"
+
+namespace device {
+
+NfcTag::NfcTag() {
+}
+
+NfcTag::~NfcTag() {
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_tag.h b/device/nfc/nfc_tag.h
new file mode 100644
index 0000000..650f37b
--- /dev/null
+++ b/device/nfc/nfc_tag.h
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_NFC_NFC_TAG_H_
+#define DEVICE_NFC_NFC_TAG_H_
+
+#include "device/nfc/nfc_tag_technology.h"
+
+namespace device {
+
+// NfcTag represents a remote NFC tag. An NFC tag is a passive NFC device,
+// powered by the NFC field of the local adapter while it is in range. Tags
+// can come in many forms, such as stickers, key fobs, or even embedded in a
+// more sofisticated device.
+//
+// Tags can have a wide range of capabilities. Simple tags just offer
+// read/write semantics, and contain some one time programmable areas to make
+// read-only. More complex tags offer math operations and per-sector access
+// control and authentication. The most sophisticated tags contain operating
+// environments allowing complex interactions with the code executing on the
+// tag.
+//
+// The NfcTag class facilitates possible interactions with a tag. The most
+// common usage of a tag is to exchange NDEF messages, but different kinds of
+// I/O can be performed using the NfcTagTechnology classes.
+class NfcTag {
+ public:
+ // NFC tag types.
+ enum TagType {
+ kTagType1,
+ kTagType2,
+ kTagType3,
+ kTagType4
+ };
+
+ // NFC protocols that a tag can support. A tag will usually support only one
+ // of these.
+ enum Protocol {
+ kProtocolFelica,
+ kProtocolIsoDep,
+ kProtocolJewel,
+ kProtocolMifare,
+ kProtocolNfcDep
+ };
+
+ // Interface for observing changes from NFC tags.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // This method will be called when an NDEF message |message|, stored on the
+ // NFC tag |tag| has been read. Although NDEF is the most common record
+ // storage format for NFC tags, not all tags support it. This method won't
+ // be called if there are no records on an NDEF compliant tag or if the tag
+ // doesn't support NDEF.
+ virtual void RecordsReceived(NfcTag* tag, const NfcNdefMessage& message) {}
+ };
+
+ virtual ~NfcTag();
+
+ // Adds and removes observers for events on this NFC tag. If monitoring
+ // multiple tags, check the |tag| parameter of observer methods to determine
+ // which tag is issuing the event.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Returns the unique identifier assigned to this tag.
+ virtual std::string GetIdentifier() const = 0;
+
+ // Returns the current tag's NFC forum specified "type".
+ virtual TagType GetType() const = 0;
+
+ // Returns true, if this tag is read-only and cannot be written to.
+ virtual bool IsReadOnly() const = 0;
+
+ // Returns the current tag's supported NFC protocol.
+ virtual Protocol GetSupportedProtocol() const = 0;
+
+ // Returns a bitmask of the tag I/O technologies supported by this tag.
+ virtual NfcTagTechnology::TechnologyTypeMask
+ GetSupportedTechnologies() const = 0;
+
+ protected:
+ NfcTag();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NfcTag);
+};
+
+} // namespace device
+
+#endif // DEVICE_NFC_NFC_TAG_H_
diff --git a/device/nfc/nfc_tag_technology.cc b/device/nfc/nfc_tag_technology.cc
new file mode 100644
index 0000000..fa2b66a
--- /dev/null
+++ b/device/nfc/nfc_tag_technology.cc
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/nfc/nfc_tag_technology.h"
+
+#include "device/nfc/nfc_tag.h"
+
+namespace device {
+
+NfcTagTechnology::NfcTagTechnology(NfcTag* tag) : tag_(tag) {
+}
+
+NfcTagTechnology::NfcTagTechnology() : tag_(NULL) {
+}
+
+NfcTagTechnology::~NfcTagTechnology() {
+}
+
+bool NfcNdefTagTechnology::IsSupportedByTag() const {
+ return tag() && (tag()->GetSupportedTechnologies() &
+ NfcTagTechnology::kTechnologyTypeNdef);
+}
+
+NfcNdefTagTechnology::NfcNdefTagTechnology(NfcTag* tag)
+ : NfcTagTechnology(tag) {
+}
+
+NfcNdefTagTechnology::~NfcNdefTagTechnology() {
+}
+
+// static
+NfcNdefTagTechnology* NfcNdefTagTechnology::Create(NfcTag* tag) {
+ // TODO(armansito): Create and return platform-specific implementation
+ // instances here.
+ return NULL;
+}
+
+} // namespace device
diff --git a/device/nfc/nfc_tag_technology.h b/device/nfc/nfc_tag_technology.h
new file mode 100644
index 0000000..c5d1c19
--- /dev/null
+++ b/device/nfc/nfc_tag_technology.h
@@ -0,0 +1,100 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_NFC_NFC_TAG_TECHNOLOGY_H_
+#define DEVICE_NFC_NFC_TAG_TECHNOLOGY_H_
+
+#include "base/callback.h"
+#include "device/nfc/nfc_ndef_record.h"
+
+namespace device {
+
+class NfcTag;
+
+// NfcTagTechnology represents an NFC technology that allows a certain type of
+// I/O operation on an NFC tag. NFC tags can support a wide array of protocols.
+// The NfcTagTechnology hierarchy allows both raw and high-level I/O operations
+// on NFC tags.
+class NfcTagTechnology {
+ public:
+ // The various I/O technologies that an NFC tag can support.
+ enum TechnologyType {
+ kTechnologyTypeNfcA = 1 << 0,
+ kTechnologyTypeNfcB = 1 << 1,
+ kTechnologyTypeNfcF = 1 << 2,
+ kTechnologyTypeNfcV = 1 << 3,
+ kTechnologyTypeIsoDep = 1 << 4,
+ kTechnologyTypeNdef = 1 << 5
+ };
+ typedef uint32 TechnologyTypeMask;
+
+ virtual ~NfcTagTechnology();
+
+ // Returns true, if the underlying tag supports the NFC tag technology that
+ // this instance represents.
+ virtual bool IsSupportedByTag() const = 0;
+
+ // Returns a pointer to the associated NfcTag instance.
+ NfcTag* tag() const { return tag_; }
+
+ protected:
+ // Constructs a technology instance, where |tag| is the NFC tag that this
+ // instance will operate on. Clients aren't allowed to instantiate classes
+ // directly. They should use the static "Create" methods defined in each
+ // subclass to obtain the platform specific implementation.
+ explicit NfcTagTechnology(NfcTag* tag);
+
+ private:
+ NfcTagTechnology();
+
+ // The underlying NfcTag instance that data exchange operations through this
+ // instance are performed on.
+ NfcTag* tag_;
+
+ DISALLOW_COPY_AND_ASSIGN(NfcTagTechnology);
+};
+
+// NfcNdefTagTechnology allows reading and writing NDEF messages to a tag. This
+// is the most commonly used data exchange format in NFC.
+class NfcNdefTagTechnology : public NfcTagTechnology {
+ public:
+ // The ErrorCallback is used by methods to asynchronously report errors.
+ typedef base::Closure ErrorCallback;
+
+ virtual ~NfcNdefTagTechnology();
+
+ // NfcTagTechnology override.
+ virtual bool IsSupportedByTag() const OVERRIDE;
+
+ // Returns all NDEF records that were received from the tag in the form of an
+ // NDEF message. If the returned NDEF message contains no records, this only
+ // means that no records have yet been received from the tag. Users should
+ // use this method in conjunction with the NfcTag::Observer::RecordsReceived
+ // method to be notified when the records are ready.
+ virtual NfcNdefMessage GetNdefMessage() const = 0;
+
+ // Writes the given NDEF message to the underlying tag, overwriting any
+ // existing NDEF message on it. On success, |callback| will be invoked. On
+ // failure, |error_callback| will be invoked. This method can fail, if the
+ // underlying tag does not support NDEF as a technology.
+ virtual void WriteNdefMessage(const NfcNdefMessage& message,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Static factory method for constructing an instance. The ownership of the
+ // returned instance belongs to the caller. Returns NULL, if NFC is not
+ // supported on the current platform.
+ static NfcNdefTagTechnology* Create(NfcTag* tag);
+
+ private:
+ // Constructs a technology instance, where |tag| is the NFC tag that this
+ // instance will operate on.
+ explicit NfcNdefTagTechnology(NfcTag* tag);
+
+ DISALLOW_COPY_AND_ASSIGN(NfcNdefTagTechnology);
+};
+
+} // namespace device
+
+#endif // DEVICE_NFC_NFC_TAG_TECHNOLOGY_H_