Home | History | Annotate | Download | only in nfc
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "device/nfc/nfc_tag_technology_chromeos.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "chromeos/dbus/dbus_thread_manager.h"
      9 #include "device/nfc/nfc_ndef_record_utils_chromeos.h"
     10 #include "device/nfc/nfc_tag_chromeos.h"
     11 
     12 using device::NfcNdefMessage;
     13 using device::NfcNdefRecord;
     14 
     15 namespace chromeos {
     16 
     17 namespace {
     18 
     19 typedef std::vector<dbus::ObjectPath> ObjectPathVector;
     20 
     21 }  // namespace
     22 
     23 NfcNdefTagTechnologyChromeOS::NfcNdefTagTechnologyChromeOS(NfcTagChromeOS* tag)
     24     : NfcNdefTagTechnology(tag),
     25       object_path_(tag->object_path()),
     26       weak_ptr_factory_(this) {
     27   DCHECK(tag);
     28   // Create record objects for all records that were received before.
     29   const ObjectPathVector& records =
     30       DBusThreadManager::Get()->GetNfcRecordClient()->
     31           GetRecordsForTag(object_path_);
     32   for (ObjectPathVector::const_iterator iter = records.begin();
     33        iter != records.end(); ++iter) {
     34     AddRecord(*iter);
     35   }
     36   DBusThreadManager::Get()->GetNfcRecordClient()->AddObserver(this);
     37 }
     38 
     39 NfcNdefTagTechnologyChromeOS::~NfcNdefTagTechnologyChromeOS() {
     40   DBusThreadManager::Get()->GetNfcRecordClient()->RemoveObserver(this);
     41   STLDeleteValues(&records_);
     42 }
     43 
     44 void NfcNdefTagTechnologyChromeOS::AddObserver(
     45     NfcNdefTagTechnology::Observer* observer) {
     46   observers_.AddObserver(observer);
     47 }
     48 
     49 void NfcNdefTagTechnologyChromeOS::RemoveObserver(
     50     NfcNdefTagTechnology::Observer* observer) {
     51   observers_.RemoveObserver(observer);
     52 }
     53 
     54 const NfcNdefMessage& NfcNdefTagTechnologyChromeOS::GetNdefMessage() const {
     55   return message_;
     56 }
     57 
     58 void NfcNdefTagTechnologyChromeOS::WriteNdef(
     59     const device::NfcNdefMessage& message,
     60     const base::Closure& callback,
     61     const ErrorCallback& error_callback) {
     62   if (message.records().empty()) {
     63     LOG(ERROR) << "Given NDEF message is empty. Cannot write it.";
     64     error_callback.Run();
     65     return;
     66   }
     67   if (!tag()->IsReady()) {
     68     LOG(ERROR) << "The tag is not ready yet: " << tag()->GetIdentifier();
     69     error_callback.Run();
     70     return;
     71   }
     72   // TODO(armansito): neard currently supports writing only one NDEF record
     73   // to a tag and won't support multiple records until 0.15. Until then, report
     74   // failure if |message| contains more than one record.
     75   if (message.records().size() > 1) {
     76     LOG(ERROR) << "Currently, writing only 1 NDEF record is supported.";
     77     error_callback.Run();
     78     return;
     79   }
     80   const NfcNdefRecord* record = message.records()[0];
     81   base::DictionaryValue attributes;
     82   if (!nfc_ndef_record_utils::NfcNdefRecordToDBusAttributes(
     83           record, &attributes)) {
     84     LOG(ERROR) << "Failed to extract NDEF record fields for NDEF push.";
     85     error_callback.Run();
     86     return;
     87   }
     88   DBusThreadManager::Get()->GetNfcTagClient()->Write(
     89       object_path_,
     90       attributes,
     91       base::Bind(&NfcNdefTagTechnologyChromeOS::OnWriteNdefMessage,
     92                  weak_ptr_factory_.GetWeakPtr(), callback),
     93       base::Bind(&NfcNdefTagTechnologyChromeOS::OnWriteNdefMessageError,
     94                  weak_ptr_factory_.GetWeakPtr(), error_callback));
     95 }
     96 
     97 void NfcNdefTagTechnologyChromeOS::RecordAdded(
     98     const dbus::ObjectPath& object_path) {
     99   // Don't create the record object yet. Instead, wait until all record
    100   // properties have been received and construct the object and notify observers
    101   // then.
    102   VLOG(1) << "Record added: " << object_path.value() << ". Waiting until "
    103           "all properties have been fetched to create record object.";
    104 }
    105 
    106 void NfcNdefTagTechnologyChromeOS::RecordRemoved(
    107     const dbus::ObjectPath& object_path) {
    108   NdefRecordMap::iterator iter = records_.find(object_path);
    109   if (iter == records_.end())
    110     return;
    111   VLOG(1) << "Lost remote NDEF record object: " << object_path.value()
    112           << ", removing record.";
    113   NfcNdefRecord* record = iter->second;
    114   message_.RemoveRecord(record);
    115   delete record;
    116   records_.erase(iter);
    117 }
    118 
    119 void NfcNdefTagTechnologyChromeOS::RecordPropertiesReceived(
    120     const dbus::ObjectPath& object_path) {
    121   VLOG(1) << "Record properties received for: " << object_path.value();
    122 
    123   // Check if the found record belongs to this tag.
    124   bool record_found = false;
    125   const ObjectPathVector& records =
    126       DBusThreadManager::Get()->GetNfcRecordClient()->
    127           GetRecordsForTag(object_path_);
    128   for (ObjectPathVector::const_iterator iter = records.begin();
    129        iter != records.end(); ++iter) {
    130     if (*iter == object_path) {
    131       record_found = true;
    132       break;
    133     }
    134   }
    135   if (!record_found) {
    136     VLOG(1) << "Record \"" << object_path.value() << "\" doesn't belong to this"
    137             << " tag. Ignoring.";
    138     return;
    139   }
    140   AddRecord(object_path);
    141 }
    142 
    143 void NfcNdefTagTechnologyChromeOS::OnWriteNdefMessage(
    144     const base::Closure& callback) {
    145   callback.Run();
    146 }
    147 
    148 void NfcNdefTagTechnologyChromeOS::OnWriteNdefMessageError(
    149     const ErrorCallback& error_callback,
    150     const std::string& error_name,
    151     const std::string& error_message) {
    152   LOG(ERROR) << object_path_.value() << ": Failed to Push NDEF message: "
    153              << error_name << ": " << error_message;
    154   error_callback.Run();
    155 }
    156 
    157 void NfcNdefTagTechnologyChromeOS::AddRecord(
    158     const dbus::ObjectPath& object_path) {
    159   // Ignore this call if an entry for this record already exists.
    160   if (records_.find(object_path) != records_.end()) {
    161     VLOG(1) << "Record object for remote \"" << object_path.value()
    162             << "\" already exists.";
    163     return;
    164   }
    165 
    166   NfcRecordClient::Properties* record_properties =
    167       DBusThreadManager::Get()->GetNfcRecordClient()->
    168           GetProperties(object_path);
    169   DCHECK(record_properties);
    170 
    171   NfcNdefRecord* record = new NfcNdefRecord();
    172   if (!nfc_ndef_record_utils::RecordPropertiesToNfcNdefRecord(
    173           record_properties, record)) {
    174     LOG(ERROR) << "Failed to create record object for record with object "
    175                << "path \"" << object_path.value() << "\"";
    176     delete record;
    177     return;
    178   }
    179 
    180   message_.AddRecord(record);
    181   records_[object_path] = record;
    182   FOR_EACH_OBSERVER(NfcNdefTagTechnology::Observer, observers_,
    183                     RecordReceived(tag(), record));
    184 }
    185 
    186 }  // namespace chromeos
    187