// 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 "chromeos/dbus/nfc_record_client.h" #include "base/bind.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "chromeos/dbus/nfc_device_client.h" #include "chromeos/dbus/nfc_tag_client.h" #include "dbus/bus.h" #include "third_party/cros_system_api/dbus/service_constants.h" using chromeos::nfc_client_helpers::DBusObjectMap; using chromeos::nfc_client_helpers::ObjectProxyTree; namespace chromeos { NfcRecordClient::Properties::Properties( dbus::ObjectProxy* object_proxy, const PropertyChangedCallback& callback) : NfcPropertySet(object_proxy, nfc_record::kNfcRecordInterface, callback) { RegisterProperty(nfc_record::kTypeProperty, &type); RegisterProperty(nfc_record::kLanguageProperty, &language); RegisterProperty(nfc_record::kEncodingProperty, &encoding); RegisterProperty(nfc_record::kRepresentationProperty, &representation); RegisterProperty(nfc_record::kUriProperty, &uri); RegisterProperty(nfc_record::kMimeTypeProperty, &mime_type); RegisterProperty(nfc_record::kSizeProperty, &size); RegisterProperty(nfc_record::kActionProperty, &action); } NfcRecordClient::Properties::~Properties() { } // The NfcRecordClient implementation used in production. class NfcRecordClientImpl : public NfcRecordClient, public NfcDeviceClient::Observer, public NfcTagClient::Observer, public DBusObjectMap::Delegate { public: explicit NfcRecordClientImpl(NfcDeviceClient* device_client, NfcTagClient* tag_client) : bus_(NULL), device_client_(device_client), tag_client_(tag_client), weak_ptr_factory_(this) { DCHECK(device_client); DCHECK(tag_client); } ~NfcRecordClientImpl() override { DCHECK(device_client_); DCHECK(tag_client_); device_client_->RemoveObserver(this); tag_client_->RemoveObserver(this); } // NfcRecordClient override. void AddObserver(NfcRecordClient::Observer* observer) override { DCHECK(observer); observers_.AddObserver(observer); } // NfcRecordClient override. void RemoveObserver(NfcRecordClient::Observer* observer) override { DCHECK(observer); observers_.RemoveObserver(observer); } std::vector GetRecordsForDevice( const dbus::ObjectPath& device_path) override { DBusObjectMap* object_map = devices_and_tags_to_object_maps_.GetObjectMap(device_path); if (!object_map) return std::vector(); return object_map->GetObjectPaths(); } std::vector GetRecordsForTag( const dbus::ObjectPath& tag_path) override { return GetRecordsForDevice(tag_path); } // NfcRecordClient override. Properties* GetProperties(const dbus::ObjectPath& object_path) override { return static_cast( devices_and_tags_to_object_maps_.FindObjectProperties(object_path)); } protected: // DBusClient override. void Init(dbus::Bus* bus) override { VLOG(1) << "Creating NfcRecordClient impl"; DCHECK(bus); bus_ = bus; DCHECK(device_client_); DCHECK(tag_client_); device_client_->AddObserver(this); tag_client_->AddObserver(this); } private: // NfcDeviceClient::Observer override. void DeviceAdded(const dbus::ObjectPath& object_path) override { VLOG(1) << "Device added. Creating map for record proxies belonging to " << "device: " << object_path.value(); devices_and_tags_to_object_maps_.CreateObjectMap( object_path, nfc_record::kNfcRecordServiceName, this, bus_); } // NfcDeviceClient::Observer override. void DeviceRemoved(const dbus::ObjectPath& object_path) override { // Neard doesn't send out property changed signals for the records that // are removed when the device they belong to is removed. Clean up the // object proxies for records that belong to the removed device. // Note: DBusObjectMap guarantees that the Properties structure for the // removed adapter will be valid before this method returns. VLOG(1) << "Device removed. Cleaning up record proxies belonging to " << "device: " << object_path.value(); devices_and_tags_to_object_maps_.RemoveObjectMap(object_path); } // NfcDeviceClient::Observer override. void DevicePropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name) override { // Update the record proxies using records from the device. DCHECK(device_client_); NfcDeviceClient::Properties* device_properties = device_client_->GetProperties(object_path); // Ignore changes to properties other than "Records". if (property_name != device_properties->records.name()) return; // Update known records. VLOG(1) << "NFC records changed."; const std::vector& received_records = device_properties->records.value(); DBusObjectMap* object_map = devices_and_tags_to_object_maps_.GetObjectMap(object_path); DCHECK(object_map); object_map->UpdateObjects(received_records); } // NfcTagClient::Observer override. void TagAdded(const dbus::ObjectPath& object_path) override { VLOG(1) << "Tag added. Creating map for record proxies belonging to " << "tag: " << object_path.value(); devices_and_tags_to_object_maps_.CreateObjectMap( object_path, nfc_record::kNfcRecordServiceName, this, bus_); } // NfcTagClient::Observer override. void TagRemoved(const dbus::ObjectPath& object_path) override { // Neard doesn't send out property changed signals for the records that // are removed when the tag they belong to is removed. Clean up the // object proxies for records that belong to the removed tag. // Note: DBusObjectMap guarantees that the Properties structure for the // removed adapter will be valid before this method returns. VLOG(1) << "Tag removed. Cleaning up record proxies belonging to " << "tag: " << object_path.value(); devices_and_tags_to_object_maps_.RemoveObjectMap(object_path); } // NfcTagClient::Observer override. void TagPropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name) override { // Update the record proxies using records from the tag. DCHECK(device_client_); NfcTagClient::Properties* tag_properties = tag_client_->GetProperties(object_path); // Ignore changes to properties other than "Records". if (property_name != tag_properties->records.name()) return; // Update known records. VLOG(1) << "NFC records changed."; const std::vector& received_records = tag_properties->records.value(); DBusObjectMap* object_map = devices_and_tags_to_object_maps_.GetObjectMap(object_path); DCHECK(object_map); object_map->UpdateObjects(received_records); // When rewriting the record to a tag, neard fires a property changed // signal for the tags "Records" property, without creating a new object // path. Sync the properties of all records here, in case Update objects // doesn't do it. VLOG(1) << "Fetch properties for all records."; object_map->RefreshAllProperties(); } // nfc_client_helpers::DBusObjectMap::Delegate override. NfcPropertySet* CreateProperties(dbus::ObjectProxy* object_proxy) override { Properties* properties = new Properties( object_proxy, base::Bind(&NfcRecordClientImpl::OnPropertyChanged, weak_ptr_factory_.GetWeakPtr(), object_proxy->object_path())); properties->SetAllPropertiesReceivedCallback( base::Bind(&NfcRecordClientImpl::OnPropertiesReceived, weak_ptr_factory_.GetWeakPtr(), object_proxy->object_path())); return properties; } // nfc_client_helpers::DBusObjectMap::Delegate override. void ObjectAdded(const dbus::ObjectPath& object_path) override { FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_, RecordAdded(object_path)); } // nfc_client_helpers::DBusObjectMap::Delegate override. void ObjectRemoved(const dbus::ObjectPath& object_path) override { FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_, RecordRemoved(object_path)); } // Called by NfcPropertySet when a property value is changed, either by // result of a signal or response to a GetAll() or Get() call. void OnPropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name) { VLOG(1) << "Record property changed; Path: " << object_path.value() << " Property: " << property_name; FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_, RecordPropertyChanged(object_path, property_name)); } // Called by NfcPropertySet when all properties have been processed as a // result of a call to GetAll. void OnPropertiesReceived(const dbus::ObjectPath& object_path) { VLOG(1) << "All record properties received; Path: " << object_path.value(); FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_, RecordPropertiesReceived(object_path)); } // We maintain a pointer to the bus to be able to request proxies for // new NFC records that appear. dbus::Bus* bus_; // List of observers interested in event notifications. base::ObserverList observers_; // Mapping from object paths to object proxies and properties structures that // were already created by us. Record objects belong to either Tag or Device // objects. This structure stores a different DBusObjectMap for each known // device and tag. ObjectProxyTree devices_and_tags_to_object_maps_; // The device and tag clients that we listen to events notifications from. NfcDeviceClient* device_client_; NfcTagClient* tag_client_; // Weak pointer factory for generating 'this' pointers that might live longer // than we do. // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(NfcRecordClientImpl); }; NfcRecordClient::NfcRecordClient() { } NfcRecordClient::~NfcRecordClient() { } NfcRecordClient* NfcRecordClient::Create(NfcDeviceClient* device_client, NfcTagClient* tag_client) { return new NfcRecordClientImpl(device_client, tag_client); } } // namespace chromeos