• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NfcPeerChromeOS(const dbus::ObjectPath & object_path)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 
~NfcPeerChromeOS()42 NfcPeerChromeOS::~NfcPeerChromeOS() {
43   DBusThreadManager::Get()->GetNfcRecordClient()->RemoveObserver(this);
44   STLDeleteValues(&records_);
45 }
46 
AddObserver(device::NfcPeer::Observer * observer)47 void NfcPeerChromeOS::AddObserver(device::NfcPeer::Observer* observer) {
48   DCHECK(observer);
49   observers_.AddObserver(observer);
50 }
51 
RemoveObserver(device::NfcPeer::Observer * observer)52 void NfcPeerChromeOS::RemoveObserver(device::NfcPeer::Observer* observer) {
53   DCHECK(observer);
54   observers_.RemoveObserver(observer);
55 }
56 
GetIdentifier() const57 std::string NfcPeerChromeOS::GetIdentifier() const {
58   return object_path_.value();
59 }
60 
GetNdefMessage() const61 const NfcNdefMessage& NfcPeerChromeOS::GetNdefMessage() const {
62   return message_;
63 }
64 
PushNdef(const NfcNdefMessage & message,const base::Closure & callback,const ErrorCallback & error_callback)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 
StartHandover(HandoverType handover_type,const base::Closure & callback,const ErrorCallback & error_callback)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 
RecordAdded(const dbus::ObjectPath & object_path)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 
RecordRemoved(const dbus::ObjectPath & object_path)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 
RecordPropertiesReceived(const dbus::ObjectPath & object_path)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 
OnPushNdef(const base::Closure & callback)154 void NfcPeerChromeOS::OnPushNdef(const base::Closure& callback) {
155   callback.Run();
156 }
157 
OnPushNdefError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)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 
AddRecord(const dbus::ObjectPath & object_path)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