diff options
author | armansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-03 10:37:15 +0000 |
---|---|---|
committer | armansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-03 10:37:15 +0000 |
commit | b763b84f66ae45588718cff2ef53ba0b91b4f66a (patch) | |
tree | 6fa077e3240cc045d653ccb28257c6bf97328a22 /device | |
parent | 3aeb282799da9acf2f6339e4e2c6461c67a049f7 (diff) | |
download | chromium_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.gyp | 2 | ||||
-rw-r--r-- | device/nfc/DEPS | 5 | ||||
-rw-r--r-- | device/nfc/nfc.gyp | 41 | ||||
-rw-r--r-- | device/nfc/nfc_adapter.cc | 53 | ||||
-rw-r--r-- | device/nfc/nfc_adapter.h | 193 | ||||
-rw-r--r-- | device/nfc/nfc_adapter_factory.cc | 24 | ||||
-rw-r--r-- | device/nfc/nfc_adapter_factory.h | 33 | ||||
-rw-r--r-- | device/nfc/nfc_ndef_record.cc | 213 | ||||
-rw-r--r-- | device/nfc/nfc_ndef_record.h | 161 | ||||
-rw-r--r-- | device/nfc/nfc_ndef_record_unittest.cc | 238 | ||||
-rw-r--r-- | device/nfc/nfc_peer.cc | 15 | ||||
-rw-r--r-- | device/nfc/nfc_peer.h | 92 | ||||
-rw-r--r-- | device/nfc/nfc_tag.cc | 15 | ||||
-rw-r--r-- | device/nfc/nfc_tag.h | 93 | ||||
-rw-r--r-- | device/nfc/nfc_tag_technology.cc | 39 | ||||
-rw-r--r-- | device/nfc/nfc_tag_technology.h | 100 |
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_ |