blob: 4ef1804b85725ed4b2993dd7e98b011276d9b3ad [file] [log] [blame]
// 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 <string>
#include <vector>
#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<dbus::ObjectPath> 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