blob: 25d1b240daeafe5e63c43e4f48272380fc2be4ee [file] [log] [blame]
// Copyright 2014 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_tag_technology_chromeos.h"
#include "base/stl_util.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "device/nfc/nfc_ndef_record_utils_chromeos.h"
#include "device/nfc/nfc_tag_chromeos.h"
using device::NfcNdefMessage;
using device::NfcNdefRecord;
namespace chromeos {
namespace {
typedef std::vector<dbus::ObjectPath> ObjectPathVector;
} // namespace
NfcNdefTagTechnologyChromeOS::NfcNdefTagTechnologyChromeOS(NfcTagChromeOS* tag)
: NfcNdefTagTechnology(tag),
object_path_(tag->object_path()),
weak_ptr_factory_(this) {
DCHECK(tag);
// Create record objects for all records that were received before.
const ObjectPathVector& records =
DBusThreadManager::Get()->GetNfcRecordClient()->
GetRecordsForTag(object_path_);
for (ObjectPathVector::const_iterator iter = records.begin();
iter != records.end(); ++iter) {
AddRecord(*iter);
}
DBusThreadManager::Get()->GetNfcRecordClient()->AddObserver(this);
}
NfcNdefTagTechnologyChromeOS::~NfcNdefTagTechnologyChromeOS() {
DBusThreadManager::Get()->GetNfcRecordClient()->RemoveObserver(this);
STLDeleteValues(&records_);
}
void NfcNdefTagTechnologyChromeOS::AddObserver(
NfcNdefTagTechnology::Observer* observer) {
observers_.AddObserver(observer);
}
void NfcNdefTagTechnologyChromeOS::RemoveObserver(
NfcNdefTagTechnology::Observer* observer) {
observers_.RemoveObserver(observer);
}
const NfcNdefMessage& NfcNdefTagTechnologyChromeOS::GetNdefMessage() const {
return message_;
}
void NfcNdefTagTechnologyChromeOS::WriteNdef(
const device::NfcNdefMessage& message,
const base::Closure& callback,
const ErrorCallback& error_callback) {
if (message.records().empty()) {
LOG(ERROR) << "Given NDEF message is empty. Cannot write it.";
error_callback.Run();
return;
}
if (!tag()->IsReady()) {
LOG(ERROR) << "The tag is not ready yet: " << tag()->GetIdentifier();
error_callback.Run();
return;
}
// TODO(armansito): neard currently supports writing only one NDEF record
// to a tag 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, writing 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()->GetNfcTagClient()->Write(
object_path_,
attributes,
base::Bind(&NfcNdefTagTechnologyChromeOS::OnWriteNdefMessage,
weak_ptr_factory_.GetWeakPtr(), callback),
base::Bind(&NfcNdefTagTechnologyChromeOS::OnWriteNdefMessageError,
weak_ptr_factory_.GetWeakPtr(), error_callback));
}
void NfcNdefTagTechnologyChromeOS::RecordAdded(
const dbus::ObjectPath& object_path) {
// Don't create the record object yet. Instead, wait until all record
// properties have been received and construct 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 NfcNdefTagTechnologyChromeOS::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 NfcNdefTagTechnologyChromeOS::RecordPropertiesReceived(
const dbus::ObjectPath& object_path) {
VLOG(1) << "Record properties received for: " << object_path.value();
// Check if the found record belongs to this tag.
bool record_found = false;
const ObjectPathVector& records =
DBusThreadManager::Get()->GetNfcRecordClient()->
GetRecordsForTag(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"
<< " tag. Ignoring.";
return;
}
AddRecord(object_path);
}
void NfcNdefTagTechnologyChromeOS::OnWriteNdefMessage(
const base::Closure& callback) {
callback.Run();
}
void NfcNdefTagTechnologyChromeOS::OnWriteNdefMessageError(
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 NfcNdefTagTechnologyChromeOS::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(NfcNdefTagTechnology::Observer, observers_,
RecordReceived(tag(), record));
}
} // namespace chromeos