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