// 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_chromeos.h" #include #include #include "base/logging.h" #include "base/stl_util.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/nfc_device_client.h" #include "device/nfc/nfc_ndef_record_utils_chromeos.h" #include "third_party/cros_system_api/dbus/service_constants.h" using device::NfcNdefMessage; using device::NfcNdefRecord; namespace chromeos { namespace { typedef std::vector ObjectPathVector; } // namespace NfcPeerChromeOS::NfcPeerChromeOS(const dbus::ObjectPath& object_path) : object_path_(object_path), weak_ptr_factory_(this) { // Create record objects for all records that were received before. const ObjectPathVector& records = DBusThreadManager::Get()->GetNfcRecordClient()-> GetRecordsForDevice(object_path_); for (ObjectPathVector::const_iterator iter = records.begin(); iter != records.end(); ++iter) { AddRecord(*iter); } DBusThreadManager::Get()->GetNfcRecordClient()->AddObserver(this); } NfcPeerChromeOS::~NfcPeerChromeOS() { DBusThreadManager::Get()->GetNfcRecordClient()->RemoveObserver(this); STLDeleteValues(&records_); } void NfcPeerChromeOS::AddObserver(device::NfcPeer::Observer* observer) { DCHECK(observer); observers_.AddObserver(observer); } void NfcPeerChromeOS::RemoveObserver(device::NfcPeer::Observer* observer) { DCHECK(observer); observers_.RemoveObserver(observer); } std::string NfcPeerChromeOS::GetIdentifier() const { return object_path_.value(); } const NfcNdefMessage& NfcPeerChromeOS::GetNdefMessage() const { return message_; } void NfcPeerChromeOS::PushNdef(const NfcNdefMessage& message, const base::Closure& callback, const ErrorCallback& error_callback) { if (message.records().empty()) { LOG(ERROR) << "Given NDEF message is empty. Cannot push it."; error_callback.Run(); return; } // TODO(armansito): neard currently supports pushing only one NDEF record // to a remote device and won't support multiple records until 0.15. Until // then, report failure if |message| contains more than one record. if (message.records().size() > 1) { LOG(ERROR) << "Currently, pushing only 1 NDEF record is supported."; error_callback.Run(); return; } const NfcNdefRecord* record = message.records()[0]; base::DictionaryValue attributes; if (!nfc_ndef_record_utils::NfcNdefRecordToDBusAttributes( record, &attributes)) { LOG(ERROR) << "Failed to extract NDEF record fields for NDEF push."; error_callback.Run(); return; } DBusThreadManager::Get()->GetNfcDeviceClient()->Push( object_path_, attributes, base::Bind(&NfcPeerChromeOS::OnPushNdef, weak_ptr_factory_.GetWeakPtr(), callback), base::Bind(&NfcPeerChromeOS::OnPushNdefError, weak_ptr_factory_.GetWeakPtr(), error_callback)); } void NfcPeerChromeOS::StartHandover(HandoverType handover_type, const base::Closure& callback, const ErrorCallback& error_callback) { // TODO(armansito): Initiating handover with a peer is currently not // supported. For now, return an error immediately. LOG(ERROR) << "NFC Handover currently not supported."; error_callback.Run(); } void NfcPeerChromeOS::RecordAdded(const dbus::ObjectPath& object_path) { // Don't create the record object yet. Instead, wait until all record // properties have been received and contruct the object and notify observers // then. VLOG(1) << "Record added: " << object_path.value() << ". Waiting until " << "all properties have been fetched to create record object."; } void NfcPeerChromeOS::RecordRemoved(const dbus::ObjectPath& object_path) { NdefRecordMap::iterator iter = records_.find(object_path); if (iter == records_.end()) return; VLOG(1) << "Lost remote NDEF record object: " << object_path.value() << ", removing record."; NfcNdefRecord* record = iter->second; message_.RemoveRecord(record); delete record; records_.erase(iter); } void NfcPeerChromeOS::RecordPropertiesReceived( const dbus::ObjectPath& object_path) { VLOG(1) << "Record properties received for: " << object_path.value(); // Check if the found record belongs to this device. bool record_found = false; const ObjectPathVector& records = DBusThreadManager::Get()->GetNfcRecordClient()-> GetRecordsForDevice(object_path_); for (ObjectPathVector::const_iterator iter = records.begin(); iter != records.end(); ++iter) { if (*iter == object_path) { record_found = true; break; } } if (!record_found) { VLOG(1) << "Record \"" << object_path.value() << "\" doesn't belong to this" << " device. Ignoring."; return; } AddRecord(object_path); } void NfcPeerChromeOS::OnPushNdef(const base::Closure& callback) { callback.Run(); } void NfcPeerChromeOS::OnPushNdefError(const ErrorCallback& error_callback, const std::string& error_name, const std::string& error_message) { LOG(ERROR) << object_path_.value() << ": Failed to Push NDEF message: " << error_name << ": " << error_message; error_callback.Run(); } void NfcPeerChromeOS::AddRecord(const dbus::ObjectPath& object_path) { // Ignore this call if an entry for this record already exists. if (records_.find(object_path) != records_.end()) { VLOG(1) << "Record object for remote \"" << object_path.value() << "\" already exists."; return; } NfcRecordClient::Properties* record_properties = DBusThreadManager::Get()->GetNfcRecordClient()-> GetProperties(object_path); DCHECK(record_properties); NfcNdefRecord* record = new NfcNdefRecord(); if (!nfc_ndef_record_utils::RecordPropertiesToNfcNdefRecord( record_properties, record)) { LOG(ERROR) << "Failed to create record object for record with object " << "path \"" << object_path.value() << "\""; delete record; return; } message_.AddRecord(record); records_[object_path] = record; FOR_EACH_OBSERVER(NfcPeer::Observer, observers_, RecordReceived(this, record)); } } // namespace chromeos