From f8005694519d625602c9473483fa276540506960 Mon Sep 17 00:00:00 2001 From: "armansito@chromium.org" Date: Thu, 31 Oct 2013 07:56:14 +0000 Subject: nfc: Add D-Bus clients for NFC Tag and Device interfaces. Added D-Bus client code for the NFC Tag and Device interfaces. BUG=304979 TEST=1. chromeos_unittests 2. Manually test using an external USB adapter that Tag and Device property changes are reflected in the logs. Review URL: https://codereview.chromium.org/48713006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232042 0039d316-1c4b-4281-b951-d872f2087c98 --- chromeos/chromeos.gyp | 8 + chromeos/dbus/dbus_thread_manager.cc | 25 +- chromeos/dbus/dbus_thread_manager.h | 4 + chromeos/dbus/fake_dbus_thread_manager.cc | 12 + chromeos/dbus/fake_dbus_thread_manager.h | 14 + chromeos/dbus/fake_nfc_adapter_client.cc | 9 +- chromeos/dbus/fake_nfc_adapter_client.h | 7 +- chromeos/dbus/fake_nfc_device_client.cc | 71 +++++ chromeos/dbus/fake_nfc_device_client.h | 54 ++++ chromeos/dbus/fake_nfc_tag_client.cc | 71 +++++ chromeos/dbus/fake_nfc_tag_client.h | 54 ++++ chromeos/dbus/mock_dbus_thread_manager.cc | 8 + chromeos/dbus/mock_dbus_thread_manager.h | 12 + chromeos/dbus/nfc_adapter_client.cc | 4 +- chromeos/dbus/nfc_client_helpers.cc | 2 +- chromeos/dbus/nfc_client_helpers.h | 9 +- chromeos/dbus/nfc_client_unittest.cc | 445 +++++++++++++++++++++++++++--- chromeos/dbus/nfc_device_client.cc | 248 +++++++++++++++++ chromeos/dbus/nfc_device_client.h | 119 ++++++++ chromeos/dbus/nfc_tag_client.cc | 250 +++++++++++++++++ chromeos/dbus/nfc_tag_client.h | 130 +++++++++ 21 files changed, 1501 insertions(+), 55 deletions(-) create mode 100644 chromeos/dbus/fake_nfc_device_client.cc create mode 100644 chromeos/dbus/fake_nfc_device_client.h create mode 100644 chromeos/dbus/fake_nfc_tag_client.cc create mode 100644 chromeos/dbus/fake_nfc_tag_client.h create mode 100644 chromeos/dbus/nfc_device_client.cc create mode 100644 chromeos/dbus/nfc_device_client.h create mode 100644 chromeos/dbus/nfc_tag_client.cc create mode 100644 chromeos/dbus/nfc_tag_client.h (limited to 'chromeos') diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index debcaa6..e0e53e6 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -115,8 +115,12 @@ 'dbus/fake_gsm_sms_client.h', 'dbus/fake_nfc_adapter_client.cc', 'dbus/fake_nfc_adapter_client.h', + 'dbus/fake_nfc_device_client.cc', + 'dbus/fake_nfc_device_client.h', 'dbus/fake_nfc_manager_client.cc', 'dbus/fake_nfc_manager_client.h', + 'dbus/fake_nfc_tag_client.cc', + 'dbus/fake_nfc_tag_client.h', 'dbus/fake_image_burner_client.cc', 'dbus/fake_image_burner_client.h', 'dbus/fake_shill_device_client.cc', @@ -137,10 +141,14 @@ 'dbus/nfc_adapter_client.h', 'dbus/nfc_client_helpers.cc', 'dbus/nfc_client_helpers.h', + 'dbus/nfc_device_client.cc', + 'dbus/nfc_device_client.h', 'dbus/nfc_manager_client.cc', 'dbus/nfc_manager_client.h', 'dbus/nfc_property_set.cc', 'dbus/nfc_property_set.h', + 'dbus/nfc_tag_client.cc', + 'dbus/nfc_tag_client.h', 'dbus/shill_client_helper.cc', 'dbus/shill_client_helper.h', 'dbus/shill_device_client.cc', diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc index b98e07c..164b503 100644 --- a/chromeos/dbus/dbus_thread_manager.cc +++ b/chromeos/dbus/dbus_thread_manager.cc @@ -30,7 +30,9 @@ #include "chromeos/dbus/introspectable_client.h" #include "chromeos/dbus/modem_messaging_client.h" #include "chromeos/dbus/nfc_adapter_client.h" +#include "chromeos/dbus/nfc_device_client.h" #include "chromeos/dbus/nfc_manager_client.h" +#include "chromeos/dbus/nfc_tag_client.h" #include "chromeos/dbus/permission_broker_client.h" #include "chromeos/dbus/power_manager_client.h" #include "chromeos/dbus/power_policy_controller.h" @@ -103,8 +105,11 @@ class DBusThreadManagerImpl : public DBusThreadManager { InitClient(image_burner_client_.get()); InitClient(introspectable_client_.get()); InitClient(modem_messaging_client_.get()); + // Initialize the NFC clients in the correct order. InitClient(nfc_manager_client_.get()); InitClient(nfc_adapter_client_.get()); + InitClient(nfc_device_client_.get()); + InitClient(nfc_tag_client_.get()); InitClient(permission_broker_client_.get()); InitClient(power_manager_client_.get()); InitClient(session_manager_client_.get()); @@ -269,10 +274,18 @@ class DBusThreadManagerImpl : public DBusThreadManager { return nfc_adapter_client_.get(); } + virtual NfcDeviceClient* GetNfcDeviceClient() OVERRIDE { + return nfc_device_client_.get(); + } + virtual NfcManagerClient* GetNfcManagerClient() OVERRIDE { return nfc_manager_client_.get(); } + virtual NfcTagClient* GetNfcTagClient() OVERRIDE { + return nfc_tag_client_.get(); + } + virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE { return permission_broker_client_.get(); } @@ -366,9 +379,14 @@ class DBusThreadManagerImpl : public DBusThreadManager { image_burner_client_.reset(ImageBurnerClient::Create(client_type)); introspectable_client_.reset(IntrospectableClient::Create(client_type)); modem_messaging_client_.reset(ModemMessagingClient::Create(client_type)); + // Create the NFC clients in the correct order based on their dependencies. nfc_manager_client_.reset(NfcManagerClient::Create(client_type)); nfc_adapter_client_.reset( NfcAdapterClient::Create(client_type, nfc_manager_client_.get())); + nfc_device_client_.reset( + NfcDeviceClient::Create(client_type, nfc_adapter_client_.get())); + nfc_tag_client_.reset( + NfcTagClient::Create(client_type, nfc_adapter_client_.get())); permission_broker_client_.reset( PermissionBrokerClient::Create(client_type)); power_manager_client_.reset( @@ -404,11 +422,12 @@ class DBusThreadManagerImpl : public DBusThreadManager { scoped_ptr image_burner_client_; scoped_ptr introspectable_client_; scoped_ptr modem_messaging_client_; - // NfcAdapterClient depends on NfcManagerClient. We declare NfcManagerClient - // first, so that it won't be deallocated before NfcAdapterClient is done - // cleaning up. + // The declaration order for NFC client objects is important. See + // DBusThreadManager::CreateDefaultClients for the dependencies. scoped_ptr nfc_manager_client_; scoped_ptr nfc_adapter_client_; + scoped_ptr nfc_device_client_; + scoped_ptr nfc_tag_client_; scoped_ptr permission_broker_client_; scoped_ptr system_clock_client_; scoped_ptr power_manager_client_; diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h index d0d6c3c..f0ef8b1 100644 --- a/chromeos/dbus/dbus_thread_manager.h +++ b/chromeos/dbus/dbus_thread_manager.h @@ -43,7 +43,9 @@ class ImageBurnerClient; class IntrospectableClient; class ModemMessagingClient; class NfcAdapterClient; +class NfcDeviceClient; class NfcManagerClient; +class NfcTagClient; class PermissionBrokerClient; class PowerManagerClient; class PowerPolicyController; @@ -137,7 +139,9 @@ class CHROMEOS_EXPORT DBusThreadManager { virtual IntrospectableClient* GetIntrospectableClient() = 0; virtual ModemMessagingClient* GetModemMessagingClient() = 0; virtual NfcAdapterClient* GetNfcAdapterClient() = 0; + virtual NfcDeviceClient* GetNfcDeviceClient() = 0; virtual NfcManagerClient* GetNfcManagerClient() = 0; + virtual NfcTagClient* GetNfcTagClient() = 0; virtual PermissionBrokerClient* GetPermissionBrokerClient() = 0; virtual PowerManagerClient* GetPowerManagerClient() = 0; virtual PowerPolicyController* GetPowerPolicyController() = 0; diff --git a/chromeos/dbus/fake_dbus_thread_manager.cc b/chromeos/dbus/fake_dbus_thread_manager.cc index e8f7bbb..9d7834a 100644 --- a/chromeos/dbus/fake_dbus_thread_manager.cc +++ b/chromeos/dbus/fake_dbus_thread_manager.cc @@ -15,7 +15,9 @@ #include "chromeos/dbus/fake_gsm_sms_client.h" #include "chromeos/dbus/fake_image_burner_client.h" #include "chromeos/dbus/fake_nfc_adapter_client.h" +#include "chromeos/dbus/fake_nfc_device_client.h" #include "chromeos/dbus/fake_nfc_manager_client.h" +#include "chromeos/dbus/fake_nfc_tag_client.h" #include "chromeos/dbus/fake_power_manager_client.h" #include "chromeos/dbus/fake_session_manager_client.h" #include "chromeos/dbus/fake_shill_device_client.h" @@ -41,7 +43,9 @@ FakeDBusThreadManager::FakeDBusThreadManager() fake_gsm_sms_client_(new FakeGsmSMSClient), fake_image_burner_client_(new FakeImageBurnerClient), fake_nfc_adapter_client_(new FakeNfcAdapterClient()), + fake_nfc_device_client_(new FakeNfcDeviceClient()), fake_nfc_manager_client_(new FakeNfcManagerClient()), + fake_nfc_tag_client_(new FakeNfcTagClient()), fake_session_manager_client_(new FakeSessionManagerClient), fake_shill_device_client_(new FakeShillDeviceClient), fake_shill_manager_client_(new FakeShillManagerClient), @@ -182,10 +186,18 @@ NfcAdapterClient* FakeDBusThreadManager::GetNfcAdapterClient() { return fake_nfc_adapter_client_.get(); } +NfcDeviceClient* FakeDBusThreadManager::GetNfcDeviceClient() { + return fake_nfc_device_client_.get(); +} + NfcManagerClient* FakeDBusThreadManager::GetNfcManagerClient() { return fake_nfc_manager_client_.get(); } +NfcTagClient* FakeDBusThreadManager::GetNfcTagClient() { + return fake_nfc_tag_client_.get(); +} + PermissionBrokerClient* FakeDBusThreadManager::GetPermissionBrokerClient() { NOTIMPLEMENTED(); diff --git a/chromeos/dbus/fake_dbus_thread_manager.h b/chromeos/dbus/fake_dbus_thread_manager.h index 495d2d1..c6fb556 100644 --- a/chromeos/dbus/fake_dbus_thread_manager.h +++ b/chromeos/dbus/fake_dbus_thread_manager.h @@ -28,7 +28,9 @@ class FakeCrosDisksClient; class FakeCryptohomeClient; class FakeGsmSMSClient; class FakeNfcAdapterClient; +class FakeNfcDeviceClient; class FakeNfcManagerClient; +class FakeNfcTagClient; class FakePowerManagerClient; class FakeImageBurnerClient; class FakeSessionManagerClient; @@ -75,7 +77,9 @@ class FakeDBusThreadManager : public DBusThreadManager { virtual IntrospectableClient* GetIntrospectableClient() OVERRIDE; virtual ModemMessagingClient* GetModemMessagingClient() OVERRIDE; virtual NfcAdapterClient* GetNfcAdapterClient() OVERRIDE; + virtual NfcDeviceClient* GetNfcDeviceClient() OVERRIDE; virtual NfcManagerClient* GetNfcManagerClient() OVERRIDE; + virtual NfcTagClient* GetNfcTagClient() OVERRIDE; virtual PermissionBrokerClient* GetPermissionBrokerClient() OVERRIDE; virtual PowerManagerClient* GetPowerManagerClient() OVERRIDE; virtual PowerPolicyController* GetPowerPolicyController() OVERRIDE; @@ -130,10 +134,18 @@ class FakeDBusThreadManager : public DBusThreadManager { return fake_nfc_adapter_client_.get(); } + FakeNfcDeviceClient* fake_nfc_device_client() { + return fake_nfc_device_client_.get(); + } + FakeNfcManagerClient* fake_nfc_manager_client() { return fake_nfc_manager_client_.get(); } + FakeNfcTagClient* fake_nfc_tag_client() { + return fake_nfc_tag_client_.get(); + } + FakeSessionManagerClient* fake_session_manager_client() { return fake_session_manager_client_.get(); } @@ -192,7 +204,9 @@ class FakeDBusThreadManager : public DBusThreadManager { scoped_ptr fake_gsm_sms_client_; scoped_ptr fake_image_burner_client_; scoped_ptr fake_nfc_adapter_client_; + scoped_ptr fake_nfc_device_client_; scoped_ptr fake_nfc_manager_client_; + scoped_ptr fake_nfc_tag_client_; scoped_ptr fake_session_manager_client_; scoped_ptr fake_shill_device_client_; scoped_ptr fake_shill_manager_client_; diff --git a/chromeos/dbus/fake_nfc_adapter_client.cc b/chromeos/dbus/fake_nfc_adapter_client.cc index 6ace808..f9b1688 100644 --- a/chromeos/dbus/fake_nfc_adapter_client.cc +++ b/chromeos/dbus/fake_nfc_adapter_client.cc @@ -65,19 +65,14 @@ void FakeNfcAdapterClient::StartPollLoop( const std::string& mode, const base::Closure& callback, const nfc_client_helpers::ErrorCallback& error_callback) { - VLOG(1) << "Starting fake NFC Adapter poll loop."; - VLOG(1) << "Nothing happened."; + VLOG(1) << "FakeNfcAdapterClient::StartPollLoop called. Nothing happened."; } void FakeNfcAdapterClient::StopPollLoop( const dbus::ObjectPath& object_path, const base::Closure& callback, const nfc_client_helpers::ErrorCallback& error_callback) { - VLOG(1) << "Stopping fake NFC Adapter poll loop."; -} - -void FakeNfcAdapterClient::OnPropertyChanged(const std::string& property_name) { - VLOG(1) << "Fake NFC property changed: " << property_name; + VLOG(1) << "FakeNfcAdapterClient::StopPollLoop called. Nothing happened."; } } // namespace chromeos diff --git a/chromeos/dbus/fake_nfc_adapter_client.h b/chromeos/dbus/fake_nfc_adapter_client.h index 97cab97..7c23fc3 100644 --- a/chromeos/dbus/fake_nfc_adapter_client.h +++ b/chromeos/dbus/fake_nfc_adapter_client.h @@ -37,8 +37,8 @@ class CHROMEOS_EXPORT FakeNfcAdapterClient : public NfcAdapterClient { virtual void Init(dbus::Bus* bus) OVERRIDE; virtual void AddObserver(Observer* observer) OVERRIDE; virtual void RemoveObserver(Observer* observer) OVERRIDE; - virtual Properties* GetProperties(const dbus::ObjectPath& object_path) - OVERRIDE; + virtual Properties* GetProperties( + const dbus::ObjectPath& object_path) OVERRIDE; virtual void StartPollLoop( const dbus::ObjectPath& object_path, const std::string& mode, @@ -50,9 +50,6 @@ class CHROMEOS_EXPORT FakeNfcAdapterClient : public NfcAdapterClient { const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE; private: - // Property callback passed when we create Properties* structures. - void OnPropertyChanged(const std::string& property_name); - DISALLOW_COPY_AND_ASSIGN(FakeNfcAdapterClient); }; diff --git a/chromeos/dbus/fake_nfc_device_client.cc b/chromeos/dbus/fake_nfc_device_client.cc new file mode 100644 index 0000000..6150cd9 --- /dev/null +++ b/chromeos/dbus/fake_nfc_device_client.cc @@ -0,0 +1,71 @@ +// 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/fake_nfc_device_client.h" + +#include "base/logging.h" +#include "dbus/object_path.h" + +// TODO(armansito): For now, this class doesn't do anything. Implement fake +// behavior in conjunction with unit tests while implementing the src/device +// layer. + +namespace chromeos { + +FakeNfcDeviceClient::Properties::Properties( + const PropertyChangedCallback& callback) + : NfcDeviceClient::Properties(NULL, callback) { +} + +FakeNfcDeviceClient::Properties::~Properties() { +} + +void FakeNfcDeviceClient::Properties::Get( + dbus::PropertyBase* property, + dbus::PropertySet::GetCallback callback) { + VLOG(1) << "Get " << property->name(); + callback.Run(false); +} + +void FakeNfcDeviceClient::Properties::GetAll() { + VLOG(1) << "GetAll"; +} + +void FakeNfcDeviceClient::Properties::Set( + dbus::PropertyBase* property, + dbus::PropertySet::SetCallback callback) { + VLOG(1) << "Set " << property->name(); + callback.Run(false); +} + +FakeNfcDeviceClient::FakeNfcDeviceClient() { + VLOG(1) << "Creating FakeNfcDeviceClient"; +} + +FakeNfcDeviceClient::~FakeNfcDeviceClient() { +} + +void FakeNfcDeviceClient::Init(dbus::Bus* bus) { +} + +void FakeNfcDeviceClient::AddObserver(Observer* observer) { +} + +void FakeNfcDeviceClient::RemoveObserver(Observer* observer) { +} + +FakeNfcDeviceClient::Properties* +FakeNfcDeviceClient::GetProperties(const dbus::ObjectPath& object_path) { + return NULL; +} + +void FakeNfcDeviceClient::Push( + const dbus::ObjectPath& object_path, + const std::map& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) { + VLOG(1) << "FakeNfcDeviceClient::Write called. Nothing happened."; +} + +} // namespace chromeos diff --git a/chromeos/dbus/fake_nfc_device_client.h b/chromeos/dbus/fake_nfc_device_client.h new file mode 100644 index 0000000..19806c4 --- /dev/null +++ b/chromeos/dbus/fake_nfc_device_client.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef CHROMEOS_DBUS_FAKE_NFC_DEVICE_CLIENT_H_ +#define CHROMEOS_DBUS_FAKE_NFC_DEVICE_CLIENT_H_ + +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/nfc_client_helpers.h" +#include "chromeos/dbus/nfc_device_client.h" + +namespace chromeos { + +// FakeNfcDeviceClient simulates the behavior of the NFC device objects +// and is used both in test cases in place of a mock and on the Linux desktop. +// TODO(armansito): For now, this doesn't do anything. Implement fake +// behavior in conjunction with unit tests while implementing the src/device +// layer. +class CHROMEOS_EXPORT FakeNfcDeviceClient : public NfcDeviceClient { + public: + struct Properties : public NfcDeviceClient::Properties { + explicit Properties(const PropertyChangedCallback& callback); + virtual ~Properties(); + + // dbus::PropertySet overrides. + virtual void Get(dbus::PropertyBase* property, + dbus::PropertySet::GetCallback callback) OVERRIDE; + virtual void GetAll() OVERRIDE; + virtual void Set(dbus::PropertyBase* property, + dbus::PropertySet::SetCallback callback) OVERRIDE; + }; + + FakeNfcDeviceClient(); + virtual ~FakeNfcDeviceClient(); + + // NfcDeviceClient overrides. + virtual void Init(dbus::Bus* bus) OVERRIDE; + virtual void AddObserver(Observer* observer) OVERRIDE; + virtual void RemoveObserver(Observer* observer) OVERRIDE; + virtual Properties* GetProperties( + const dbus::ObjectPath& object_path) OVERRIDE; + virtual void Push( + const dbus::ObjectPath& object_path, + const std::map& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(FakeNfcDeviceClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_FAKE_NFC_DEVICE_CLIENT_H_ diff --git a/chromeos/dbus/fake_nfc_tag_client.cc b/chromeos/dbus/fake_nfc_tag_client.cc new file mode 100644 index 0000000..a146de1 --- /dev/null +++ b/chromeos/dbus/fake_nfc_tag_client.cc @@ -0,0 +1,71 @@ +// 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/fake_nfc_tag_client.h" + +#include "base/logging.h" +#include "dbus/object_path.h" + +// TODO(armansito): For now, this class doesn't do anything. Implement fake +// behavior in conjunction with unit tests while implementing the src/device +// layer. + +namespace chromeos { + +FakeNfcTagClient::Properties::Properties( + const PropertyChangedCallback& callback) + : NfcTagClient::Properties(NULL, callback) { +} + +FakeNfcTagClient::Properties::~Properties() { +} + +void FakeNfcTagClient::Properties::Get( + dbus::PropertyBase* property, + dbus::PropertySet::GetCallback callback) { + VLOG(1) << "Get " << property->name(); + callback.Run(false); +} + +void FakeNfcTagClient::Properties::GetAll() { + VLOG(1) << "GetAll"; +} + +void FakeNfcTagClient::Properties::Set( + dbus::PropertyBase* property, + dbus::PropertySet::SetCallback callback) { + VLOG(1) << "Set " << property->name(); + callback.Run(false); +} + +FakeNfcTagClient::FakeNfcTagClient() { + VLOG(1) << "Creating FakeNfcTagClient"; +} + +FakeNfcTagClient::~FakeNfcTagClient() { +} + +void FakeNfcTagClient::Init(dbus::Bus* bus) { +} + +void FakeNfcTagClient::AddObserver(Observer* observer) { +} + +void FakeNfcTagClient::RemoveObserver(Observer* observer) { +} + +FakeNfcTagClient::Properties* +FakeNfcTagClient::GetProperties(const dbus::ObjectPath& object_path) { + return NULL; +} + +void FakeNfcTagClient::Write( + const dbus::ObjectPath& object_path, + const std::map& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) { + VLOG(1) << "FakeNfcTagClient::Write called. Nothing happened."; +} + +} // namespace chromeos diff --git a/chromeos/dbus/fake_nfc_tag_client.h b/chromeos/dbus/fake_nfc_tag_client.h new file mode 100644 index 0000000..21bf4ff --- /dev/null +++ b/chromeos/dbus/fake_nfc_tag_client.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef CHROMEOS_DBUS_FAKE_NFC_TAG_CLIENT_H_ +#define CHROMEOS_DBUS_FAKE_NFC_TAG_CLIENT_H_ + +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/nfc_client_helpers.h" +#include "chromeos/dbus/nfc_tag_client.h" + +namespace chromeos { + +// FakeNfcTagClient simulates the behavior of the NFC tag objects +// and is used both in test cases in place of a mock and on the Linux desktop. +// TODO(armansito): For now, this doesn't do anything. Implement fake +// behavior in conjunction with unit tests while implementing the src/device +// layer. +class CHROMEOS_EXPORT FakeNfcTagClient : public NfcTagClient { + public: + struct Properties : public NfcTagClient::Properties { + explicit Properties(const PropertyChangedCallback& callback); + virtual ~Properties(); + + // dbus::PropertySet overrides. + virtual void Get(dbus::PropertyBase* property, + dbus::PropertySet::GetCallback callback) OVERRIDE; + virtual void GetAll() OVERRIDE; + virtual void Set(dbus::PropertyBase* property, + dbus::PropertySet::SetCallback callback) OVERRIDE; + }; + + FakeNfcTagClient(); + virtual ~FakeNfcTagClient(); + + // NfcTagClient overrides. + virtual void Init(dbus::Bus* bus) OVERRIDE; + virtual void AddObserver(Observer* observer) OVERRIDE; + virtual void RemoveObserver(Observer* observer) OVERRIDE; + virtual Properties* GetProperties( + const dbus::ObjectPath& object_path) OVERRIDE; + virtual void Write( + const dbus::ObjectPath& object_path, + const std::map& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(FakeNfcTagClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_FAKE_NFC_TAG_CLIENT_H_ diff --git a/chromeos/dbus/mock_dbus_thread_manager.cc b/chromeos/dbus/mock_dbus_thread_manager.cc index 95901b15..f9dc873 100644 --- a/chromeos/dbus/mock_dbus_thread_manager.cc +++ b/chromeos/dbus/mock_dbus_thread_manager.cc @@ -13,7 +13,9 @@ #include "chromeos/dbus/fake_bluetooth_profile_manager_client.h" #include "chromeos/dbus/fake_gsm_sms_client.h" #include "chromeos/dbus/fake_nfc_adapter_client.h" +#include "chromeos/dbus/fake_nfc_device_client.h" #include "chromeos/dbus/fake_nfc_manager_client.h" +#include "chromeos/dbus/fake_nfc_tag_client.h" #include "chromeos/dbus/fake_shill_device_client.h" #include "chromeos/dbus/fake_shill_ipconfig_client.h" #include "chromeos/dbus/ibus/mock_ibus_client.h" @@ -60,7 +62,9 @@ MockDBusThreadManager::MockDBusThreadManager() new FakeBluetoothProfileManagerClient), fake_gsm_sms_client_(new FakeGsmSMSClient), fake_nfc_adapter_client_(new FakeNfcAdapterClient()), + fake_nfc_device_client_(new FakeNfcDeviceClient()), fake_nfc_manager_client_(new FakeNfcManagerClient()), + fake_nfc_tag_client_(new FakeNfcTagClient()), fake_shill_device_client_(new FakeShillDeviceClient), fake_shill_ipconfig_client_(new FakeShillIPConfigClient), mock_cryptohome_client_(new MockCryptohomeClient), @@ -82,8 +86,12 @@ MockDBusThreadManager::MockDBusThreadManager() .WillRepeatedly(Return(fake_bluetooth_profile_manager_client())); EXPECT_CALL(*this, GetNfcAdapterClient()) .WillRepeatedly(Return(fake_nfc_adapter_client())); + EXPECT_CALL(*this, GetNfcDeviceClient()) + .WillRepeatedly(Return(fake_nfc_device_client())); EXPECT_CALL(*this, GetNfcManagerClient()) .WillRepeatedly(Return(fake_nfc_manager_client())); + EXPECT_CALL(*this, GetNfcTagClient()) + .WillRepeatedly(Return(fake_nfc_tag_client())); EXPECT_CALL(*this, GetShillDeviceClient()) .WillRepeatedly(Return(fake_shill_device_client())); EXPECT_CALL(*this, GetShillIPConfigClient()) diff --git a/chromeos/dbus/mock_dbus_thread_manager.h b/chromeos/dbus/mock_dbus_thread_manager.h index 5fe6675..12838ad 100644 --- a/chromeos/dbus/mock_dbus_thread_manager.h +++ b/chromeos/dbus/mock_dbus_thread_manager.h @@ -27,7 +27,9 @@ class FakeBluetoothInputClient; class FakeBluetoothProfileManagerClient; class FakeGsmSMSClient; class FakeNfcAdapterClient; +class FakeNfcDeviceClient; class FakeNfcManagerClient; +class FakeNfcTagClient; class FakeShillDeviceClient; class FakeShillIPConfigClient; class MockCryptohomeClient; @@ -74,7 +76,9 @@ class MockDBusThreadManager : public DBusThreadManager { MOCK_METHOD0(GetIntrospectableClient, IntrospectableClient*(void)); MOCK_METHOD0(GetModemMessagingClient, ModemMessagingClient*(void)); MOCK_METHOD0(GetNfcAdapterClient, NfcAdapterClient*(void)); + MOCK_METHOD0(GetNfcDeviceClient, NfcDeviceClient*(void)); MOCK_METHOD0(GetNfcManagerClient, NfcManagerClient*(void)); + MOCK_METHOD0(GetNfcTagClient, NfcTagClient*(void)); MOCK_METHOD0(GetPermissionBrokerClient, PermissionBrokerClient*(void)); MOCK_METHOD0(GetPowerManagerClient, PowerManagerClient*(void)); MOCK_METHOD0(GetPowerPolicyController, PowerPolicyController*(void)); @@ -110,9 +114,15 @@ class MockDBusThreadManager : public DBusThreadManager { FakeNfcAdapterClient* fake_nfc_adapter_client() { return fake_nfc_adapter_client_.get(); } + FakeNfcDeviceClient* fake_nfc_device_client() { + return fake_nfc_device_client_.get(); + } FakeNfcManagerClient* fake_nfc_manager_client() { return fake_nfc_manager_client_.get(); } + FakeNfcTagClient* fake_nfc_tag_client() { + return fake_nfc_tag_client_.get(); + } FakeShillDeviceClient* fake_shill_device_client() { return fake_shill_device_client_.get(); } @@ -149,7 +159,9 @@ class MockDBusThreadManager : public DBusThreadManager { fake_bluetooth_profile_manager_client_; scoped_ptr fake_gsm_sms_client_; scoped_ptr fake_nfc_adapter_client_; + scoped_ptr fake_nfc_device_client_; scoped_ptr fake_nfc_manager_client_; + scoped_ptr fake_nfc_tag_client_; scoped_ptr fake_shill_device_client_; scoped_ptr fake_shill_ipconfig_client_; scoped_ptr mock_cryptohome_client_; diff --git a/chromeos/dbus/nfc_adapter_client.cc b/chromeos/dbus/nfc_adapter_client.cc index 0557dd8..040db2a 100644 --- a/chromeos/dbus/nfc_adapter_client.cc +++ b/chromeos/dbus/nfc_adapter_client.cc @@ -162,8 +162,8 @@ class NfcAdapterClientImpl } // NfcManagerClient::Observer override. - virtual void ManagerPropertyChanged(const std::string& property_name) - OVERRIDE { + virtual void ManagerPropertyChanged( + const std::string& property_name) OVERRIDE { NfcManagerClient::Properties* manager_properties = manager_client_->GetProperties(); if (!initial_adapters_received_ && diff --git a/chromeos/dbus/nfc_client_helpers.cc b/chromeos/dbus/nfc_client_helpers.cc index 12ae6c0..51889e81 100644 --- a/chromeos/dbus/nfc_client_helpers.cc +++ b/chromeos/dbus/nfc_client_helpers.cc @@ -75,7 +75,7 @@ bool DBusObjectMap::AddObject(const dbus::ObjectPath& object_path) { properties->ConnectSignals(); properties->GetAll(); VLOG(1) << "Created proxy for object with Path: " << object_path.value() - << " Service: " << service_name_; + << ", Service: " << service_name_; ObjectPropertyPair object = std::make_pair(object_proxy, properties); object_map_[object_path] = object; return true; diff --git a/chromeos/dbus/nfc_client_helpers.h b/chromeos/dbus/nfc_client_helpers.h index d910369..ed344db 100644 --- a/chromeos/dbus/nfc_client_helpers.h +++ b/chromeos/dbus/nfc_client_helpers.h @@ -64,6 +64,9 @@ class CHROMEOS_EXPORT DBusObjectMap { dbus::ObjectProxy* object_proxy) = 0; }; + typedef std::pair ObjectPropertyPair; + typedef std::map ObjectMap; + // Constructor takes in the D-Bus service name the proxies belong to and // the delegate which will be used to construct properties structures. // |service_name| must be a valid D-Bus service name, and |delegate| cannot @@ -91,10 +94,10 @@ class CHROMEOS_EXPORT DBusObjectMap { // remote object with object path |object_path|. void RemoveObject(const dbus::ObjectPath& object_path); - private: - typedef std::pair ObjectPropertyPair; - typedef std::map ObjectMap; + // Returns the underlying map. + const ObjectMap& object_map() const { return object_map_; } + private: // Returns an instance of ObjectPropertyPair by looking up |object_path| in // |object_map_|. If no entry is found, returns an instance that contains // NULL pointers. diff --git a/chromeos/dbus/nfc_client_unittest.cc b/chromeos/dbus/nfc_client_unittest.cc index f62fc42..7327d9e 100644 --- a/chromeos/dbus/nfc_client_unittest.cc +++ b/chromeos/dbus/nfc_client_unittest.cc @@ -6,7 +6,9 @@ #include "base/message_loop/message_loop.h" #include "chromeos/dbus/nfc_adapter_client.h" #include "chromeos/dbus/nfc_client_helpers.h" +#include "chromeos/dbus/nfc_device_client.h" #include "chromeos/dbus/nfc_manager_client.h" +#include "chromeos/dbus/nfc_tag_client.h" #include "dbus/mock_bus.h" #include "dbus/mock_object_proxy.h" #include "testing/gmock/include/gmock/gmock.h" @@ -29,6 +31,10 @@ const char kTestServiceName[] = "test.service.name"; const char kTestManagerPath[] = "/test/nfc/manager"; const char kTestAdapterPath0[] = "/test/nfc/adapter0"; const char kTestAdapterPath1[] = "/test/nfc/adapter1"; +const char kTestDevicePath0[] = "/test/nfc/device0"; +const char kTestDevicePath1[] = "/test/nfc/device1"; +const char kTestTagPath0[] = "/test/nfc/tag0"; +const char kTestTagPath1[] = "/test/nfc/tag1"; class MockNfcManagerObserver : public NfcManagerClient::Observer { public: @@ -45,6 +51,26 @@ class MockNfcAdapterObserver : public NfcAdapterClient::Observer { const std::string&)); }; +class MockNfcDeviceObserver : public NfcDeviceClient::Observer { + public: + MOCK_METHOD2(DeviceFound, void(const dbus::ObjectPath&, + const dbus::ObjectPath&)); + MOCK_METHOD2(DeviceLost, void(const dbus::ObjectPath&, + const dbus::ObjectPath&)); + MOCK_METHOD2(DevicePropertyChanged, void(const dbus::ObjectPath&, + const std::string&)); +}; + +class MockNfcTagObserver : public NfcTagClient::Observer { + public: + MOCK_METHOD2(TagFound, void(const dbus::ObjectPath&, + const dbus::ObjectPath&)); + MOCK_METHOD2(TagLost, void(const dbus::ObjectPath&, + const dbus::ObjectPath&)); + MOCK_METHOD2(TagPropertyChanged, void(const dbus::ObjectPath&, + const std::string&)); +}; + } // namespace class NfcClientTest : public testing::Test { @@ -71,6 +97,22 @@ class NfcClientTest : public testing::Test { mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestAdapterPath1)); + mock_device0_proxy_ = new dbus::MockObjectProxy( + mock_bus_.get(), + kTestServiceName, + dbus::ObjectPath(kTestDevicePath0)); + mock_device1_proxy_ = new dbus::MockObjectProxy( + mock_bus_.get(), + kTestServiceName, + dbus::ObjectPath(kTestDevicePath1)); + mock_tag0_proxy_ = new dbus::MockObjectProxy( + mock_bus_.get(), + kTestServiceName, + dbus::ObjectPath(kTestTagPath0)); + mock_tag1_proxy_ = new dbus::MockObjectProxy( + mock_bus_.get(), + kTestServiceName, + dbus::ObjectPath(kTestTagPath1)); // Set expectations that use NfcClientTest::OnConnectToSignal when the // client connect signals on the mock proxies. @@ -95,6 +137,22 @@ class NfcClientTest : public testing::Test { GetObjectProxy(nfc_adapter::kNfcAdapterServiceName, dbus::ObjectPath(kTestAdapterPath1))) .WillRepeatedly(Return(mock_adapter1_proxy_.get())); + EXPECT_CALL(*mock_bus_.get(), + GetObjectProxy(nfc_device::kNfcDeviceServiceName, + dbus::ObjectPath(kTestDevicePath0))) + .WillRepeatedly(Return(mock_device0_proxy_.get())); + EXPECT_CALL(*mock_bus_.get(), + GetObjectProxy(nfc_device::kNfcDeviceServiceName, + dbus::ObjectPath(kTestDevicePath1))) + .WillRepeatedly(Return(mock_device1_proxy_.get())); + EXPECT_CALL(*mock_bus_.get(), + GetObjectProxy(nfc_tag::kNfcTagServiceName, + dbus::ObjectPath(kTestTagPath0))) + .WillRepeatedly(Return(mock_tag0_proxy_.get())); + EXPECT_CALL(*mock_bus_.get(), + GetObjectProxy(nfc_tag::kNfcTagServiceName, + dbus::ObjectPath(kTestTagPath1))) + .WillRepeatedly(Return(mock_tag1_proxy_.get())); // ShutdownAndBlock will be called in TearDown. EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); @@ -105,21 +163,35 @@ class NfcClientTest : public testing::Test { adapter_client_.reset( NfcAdapterClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION, manager_client_.get())); + device_client_.reset( + NfcDeviceClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION, + adapter_client_.get())); + tag_client_.reset( + NfcTagClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION, + adapter_client_.get())); manager_client_->Init(mock_bus_.get()); adapter_client_->Init(mock_bus_.get()); + device_client_->Init(mock_bus_.get()); + tag_client_->Init(mock_bus_.get()); manager_client_->AddObserver(&mock_manager_observer_); adapter_client_->AddObserver(&mock_adapter_observer_); + device_client_->AddObserver(&mock_device_observer_); + tag_client_->AddObserver(&mock_tag_observer_); message_loop_.RunUntilIdle(); } virtual void TearDown() OVERRIDE { + tag_client_->RemoveObserver(&mock_tag_observer_); + device_client_->RemoveObserver(&mock_device_observer_); adapter_client_->RemoveObserver(&mock_adapter_observer_); manager_client_->RemoveObserver(&mock_manager_observer_); mock_bus_->ShutdownAndBlock(); } - void SendManagerAdapterAddedSignal(const dbus::ObjectPath& object_path) { + void SimulateAdapterAdded(const dbus::ObjectPath& object_path) { + EXPECT_CALL(mock_manager_observer_, AdapterAdded(object_path)); + EXPECT_CALL(mock_adapter_observer_, AdapterAdded(object_path)); dbus::Signal signal(nfc_manager::kNfcManagerInterface, nfc_manager::kAdapterAddedSignal); dbus::MessageWriter writer(&signal); @@ -128,13 +200,64 @@ class NfcClientTest : public testing::Test { manager_adapter_added_signal_callback_.Run(&signal); } - void SendManagerAdapterRemovedSignal(const dbus::ObjectPath& object_path) { + void SimulateAdapterRemoved(const dbus::ObjectPath& object_path) { + EXPECT_CALL(mock_manager_observer_, AdapterRemoved(object_path)); + EXPECT_CALL(mock_adapter_observer_, AdapterRemoved(object_path)); dbus::Signal signal(nfc_manager::kNfcManagerInterface, nfc_manager::kAdapterRemovedSignal); dbus::MessageWriter writer(&signal); writer.AppendObjectPath(object_path); ASSERT_FALSE(manager_adapter_removed_signal_callback_.is_null()); manager_adapter_removed_signal_callback_.Run(&signal); + Mock::VerifyAndClearExpectations(&mock_manager_observer_); + Mock::VerifyAndClearExpectations(&mock_adapter_observer_); + } + + void SimulateTagsChanged(const std::vector& tag_paths, + const dbus::ObjectPath& adapter_path) { + NfcAdapterClient::Properties* properties = + adapter_client_->GetProperties(adapter_path); + ASSERT_TRUE(properties); + EXPECT_CALL(mock_adapter_observer_, + AdapterPropertyChanged(adapter_path, + nfc_adapter::kTagsProperty)); + SendArrayPropertyChangedSignal( + properties, + nfc_adapter::kNfcAdapterInterface, + nfc_adapter::kTagsProperty, + tag_paths); + Mock::VerifyAndClearExpectations(&mock_adapter_observer_); + } + + void SimulateDevicesChanged(const std::vector& device_paths, + const dbus::ObjectPath& adapter_path) { + NfcAdapterClient::Properties* properties = + adapter_client_->GetProperties(adapter_path); + ASSERT_TRUE(properties); + EXPECT_CALL(mock_adapter_observer_, + AdapterPropertyChanged(adapter_path, + nfc_adapter::kDevicesProperty)); + SendArrayPropertyChangedSignal( + properties, + nfc_adapter::kNfcAdapterInterface, + nfc_adapter::kDevicesProperty, + device_paths); + Mock::VerifyAndClearExpectations(&mock_adapter_observer_); + } + + void SendArrayPropertyChangedSignal( + dbus::PropertySet* properties, + const std::string& interface, + const std::string& property_name, + std::vector object_paths) { + dbus::Signal signal(interface, nfc_common::kPropertyChangedSignal); + dbus::MessageWriter writer(&signal); + writer.AppendString(property_name); + dbus::MessageWriter variant_writer(NULL); + writer.OpenVariant("ao", &variant_writer); + variant_writer.AppendArrayOfObjectPaths(object_paths); + writer.CloseContainer(&variant_writer); + properties->ChangedReceived(&signal); } MOCK_METHOD0(SuccessCallback, void(void)); @@ -142,6 +265,14 @@ class NfcClientTest : public testing::Test { const std::string& error_message)); protected: + // The mock object proxies. + scoped_refptr mock_manager_proxy_; + scoped_refptr mock_adapter0_proxy_; + scoped_refptr mock_adapter1_proxy_; + scoped_refptr mock_device0_proxy_; + scoped_refptr mock_device1_proxy_; + scoped_refptr mock_tag0_proxy_; + scoped_refptr mock_tag1_proxy_; // The mock bus. scoped_refptr mock_bus_; // A message loop to emulate asynchronous behavior. @@ -151,13 +282,13 @@ class NfcClientTest : public testing::Test { // The D-Bus client objects under test. scoped_ptr manager_client_; scoped_ptr adapter_client_; + scoped_ptr device_client_; + scoped_ptr tag_client_; // Mock observers. MockNfcManagerObserver mock_manager_observer_; MockNfcAdapterObserver mock_adapter_observer_; - // The mock object proxies. - scoped_refptr mock_manager_proxy_; - scoped_refptr mock_adapter0_proxy_; - scoped_refptr mock_adapter1_proxy_; + MockNfcDeviceObserver mock_device_observer_; + MockNfcTagObserver mock_tag_observer_; // The signal callbacks used to simulate asychronous signals. dbus::ObjectProxy::SignalCallback manager_adapter_added_signal_callback_; dbus::ObjectProxy::SignalCallback manager_adapter_removed_signal_callback_; @@ -197,12 +328,7 @@ TEST_F(NfcClientTest, AdaptersAddedAndRemoved) { Mock::VerifyAndClearExpectations(this); // Add adapter 0. - EXPECT_CALL(mock_manager_observer_, - AdapterAdded(dbus::ObjectPath(kTestAdapterPath0))); - EXPECT_CALL(mock_adapter_observer_, - AdapterAdded(dbus::ObjectPath(kTestAdapterPath0))); - SendManagerAdapterAddedSignal(dbus::ObjectPath(kTestAdapterPath0)); - Mock::VerifyAndClearExpectations(this); + SimulateAdapterAdded(dbus::ObjectPath(kTestAdapterPath0)); // Invoking methods should succeed on adapter 0 but fail on adapter 1. EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); @@ -211,24 +337,21 @@ TEST_F(NfcClientTest, AdaptersAddedAndRemoved) { nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); - Mock::VerifyAndClearExpectations(this); - + Mock::VerifyAndClearExpectations(&mock_adapter0_proxy_); EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath1), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_adapter1_proxy_); // Add adapter 1. - EXPECT_CALL(mock_manager_observer_, - AdapterAdded(dbus::ObjectPath(kTestAdapterPath1))); - EXPECT_CALL(mock_adapter_observer_, - AdapterAdded(dbus::ObjectPath(kTestAdapterPath1))); - SendManagerAdapterAddedSignal(dbus::ObjectPath(kTestAdapterPath1)); - Mock::VerifyAndClearExpectations(this); + SimulateAdapterAdded(dbus::ObjectPath(kTestAdapterPath1)); // Invoking methods should succeed on both adapters. EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); @@ -243,19 +366,17 @@ TEST_F(NfcClientTest, AdaptersAddedAndRemoved) { nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); - Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_adapter0_proxy_); + Mock::VerifyAndClearExpectations(&mock_adapter1_proxy_); // Remove adapter 0. - EXPECT_CALL(mock_manager_observer_, - AdapterRemoved(dbus::ObjectPath(kTestAdapterPath0))); - EXPECT_CALL(mock_adapter_observer_, - AdapterRemoved(dbus::ObjectPath(kTestAdapterPath0))); - SendManagerAdapterRemovedSignal(dbus::ObjectPath(kTestAdapterPath0)); - Mock::VerifyAndClearExpectations(this); + SimulateAdapterRemoved(dbus::ObjectPath(kTestAdapterPath0)); // Invoking methods should succeed on adapter 1 but fail on adapter 0. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, @@ -269,20 +390,20 @@ TEST_F(NfcClientTest, AdaptersAddedAndRemoved) { nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); - Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_adapter0_proxy_); + Mock::VerifyAndClearExpectations(&mock_adapter1_proxy_); // Remove adapter 1. - EXPECT_CALL(mock_manager_observer_, - AdapterRemoved(dbus::ObjectPath(kTestAdapterPath1))); - EXPECT_CALL(mock_adapter_observer_, - AdapterRemoved(dbus::ObjectPath(kTestAdapterPath1))); - SendManagerAdapterRemovedSignal(dbus::ObjectPath(kTestAdapterPath1)); - Mock::VerifyAndClearExpectations(this); + SimulateAdapterRemoved(dbus::ObjectPath(kTestAdapterPath1)); // Invoking methods should fail on both adapters. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)) .Times(2); + EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0);; adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, @@ -295,4 +416,260 @@ TEST_F(NfcClientTest, AdaptersAddedAndRemoved) { base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); } +// Tests that when tags are added and removed through an adapter, all +// observers are notified and the proxies are created and removed +// accordingly. +TEST_F(NfcClientTest, TagsAddedAndRemoved) { + // Invoking methods on tags that haven't been added should fail. + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + NfcTagClient::RecordAttributes write_data; + write_data[nfc_record::kTypeProperty] = nfc_record::kTypeText; + tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(this); + + // Add adapter 0. + SimulateAdapterAdded(dbus::ObjectPath(kTestAdapterPath0)); + + // Add tag 0. + std::vector tag_paths; + tag_paths.push_back(dbus::ObjectPath(kTestTagPath0)); + EXPECT_CALL(mock_tag_observer_, + TagFound(dbus::ObjectPath(kTestTagPath0), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_tag_observer_); + + // Invoking methods should succeed on tag 0 but fail on tag 1. + EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(&mock_tag0_proxy_); + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_tag1_proxy_); + + // Add tag 1. + tag_paths.push_back(dbus::ObjectPath(kTestTagPath1)); + EXPECT_CALL(mock_tag_observer_, + TagFound(dbus::ObjectPath(kTestTagPath1), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_tag_observer_); + + // Invoking methods should succeed on both tags. + EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(&mock_tag0_proxy_); + Mock::VerifyAndClearExpectations(&mock_tag1_proxy_); + + // Remove tag 0. + tag_paths.erase(tag_paths.begin()); + EXPECT_CALL(mock_tag_observer_, + TagLost(dbus::ObjectPath(kTestTagPath0), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_tag_observer_); + + // Invoking methods should succeed on tag 1 but fail on tag 0. + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_tag0_proxy_); + EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(&mock_tag1_proxy_); + + // Remove tag 1. + tag_paths.clear(); + EXPECT_CALL(mock_tag_observer_, + TagLost(dbus::ObjectPath(kTestTagPath1), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_tag_observer_); + + // Invoking methods should fail on both tags. + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)) + .Times(2); + EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); +} + +// Tests that when devices are added and removed through an adapter, all +// observers are notified and the proxies are created and removed +// accordingly. +TEST_F(NfcClientTest, DevicesAddedAndRemoved) { + // Invoking methods on devices that haven't been added should fail. + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + NfcDeviceClient::RecordAttributes write_data; + write_data[nfc_record::kTypeProperty] = nfc_record::kTypeText; + device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(this); + + // Add adapter 0. + SimulateAdapterAdded(dbus::ObjectPath(kTestAdapterPath0)); + + // Add device 0. + std::vector device_paths; + device_paths.push_back(dbus::ObjectPath(kTestDevicePath0)); + EXPECT_CALL(mock_device_observer_, + DeviceFound(dbus::ObjectPath(kTestDevicePath0), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_device_observer_); + + // Invoking methods should succeed on device 0 but fail on device 1. + EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(&mock_device0_proxy_); + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_device1_proxy_); + + // Add device 1. + device_paths.push_back(dbus::ObjectPath(kTestDevicePath1)); + EXPECT_CALL(mock_device_observer_, + DeviceFound(dbus::ObjectPath(kTestDevicePath1), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_device_observer_); + + // Invoking methods should succeed on both devices. + EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(&mock_device0_proxy_); + Mock::VerifyAndClearExpectations(&mock_device1_proxy_); + + // Remove device 0. + device_paths.erase(device_paths.begin()); + EXPECT_CALL(mock_device_observer_, + DeviceLost(dbus::ObjectPath(kTestDevicePath0), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_device_observer_); + + // Invoking methods should succeed on device 1 but fail on device 0. + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); + EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(this); + Mock::VerifyAndClearExpectations(&mock_device0_proxy_); + EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); + device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + Mock::VerifyAndClearExpectations(&mock_device1_proxy_); + + // Remove device 1. + device_paths.clear(); + EXPECT_CALL(mock_device_observer_, + DeviceLost(dbus::ObjectPath(kTestDevicePath1), + dbus::ObjectPath(kTestAdapterPath0))); + SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); + Mock::VerifyAndClearExpectations(&mock_device_observer_); + + // Invoking methods should fail on both devices. + EXPECT_CALL(*this, + ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)) + .Times(2); + EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) + .Times(0); + device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); + device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, + base::Bind(&NfcClientTest::SuccessCallback, + base::Unretained(this)), + base::Bind(&NfcClientTest::ErrorCallback, + base::Unretained(this))); +} + } // namespace chromeos diff --git a/chromeos/dbus/nfc_device_client.cc b/chromeos/dbus/nfc_device_client.cc new file mode 100644 index 0000000..83076d2 --- /dev/null +++ b/chromeos/dbus/nfc_device_client.cc @@ -0,0 +1,248 @@ +// 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_device_client.h" + +#include + +#include "base/bind.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "chromeos/dbus/fake_nfc_device_client.h" +#include "chromeos/dbus/nfc_adapter_client.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +using chromeos::nfc_client_helpers::DBusObjectMap; + +namespace chromeos { + +namespace { + +typedef std::vector ObjectPathVector; + +} // namespace + +NfcDeviceClient::Properties::Properties( + dbus::ObjectProxy* object_proxy, + const PropertyChangedCallback& callback) + : NfcPropertySet(object_proxy, + nfc_device::kNfcDeviceInterface, + callback) { + RegisterProperty(nfc_device::kRecordsProperty, &records); +} + +NfcDeviceClient::Properties::~Properties() { +} + +// The NfcDeviceClient implementation used in production. +class NfcDeviceClientImpl : public NfcDeviceClient, + public NfcAdapterClient::Observer, + public DBusObjectMap::Delegate { + public: + explicit NfcDeviceClientImpl(NfcAdapterClient* adapter_client) + : bus_(NULL), + adapter_client_(adapter_client), + weak_ptr_factory_(this) { + DCHECK(adapter_client); + } + + virtual ~NfcDeviceClientImpl() { + adapter_client_->RemoveObserver(this); + } + + // NfcDeviceClient override. + virtual void AddObserver(NfcDeviceClient::Observer* observer) OVERRIDE { + DCHECK(observer); + observers_.AddObserver(observer); + } + + // NfcDeviceClient override. + virtual void RemoveObserver(NfcDeviceClient::Observer* observer) OVERRIDE { + DCHECK(observer); + observers_.RemoveObserver(observer); + } + + // NfcDeviceClient override. + virtual Properties* GetProperties(const dbus::ObjectPath& object_path) + OVERRIDE { + return static_cast( + object_map_->GetObjectProperties(object_path)); + } + + // NfcDeviceClient override. + virtual void Push( + const dbus::ObjectPath& object_path, + const RecordAttributes& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE { + dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path); + if (!object_proxy) { + std::string error_message = + base::StringPrintf( + "NFC device with object path \"%s\" does not exist.", + object_path.value().c_str()); + LOG(ERROR) << error_message; + error_callback.Run(nfc_client_helpers::kUnknownObjectError, + error_message); + return; + } + + // |attributes| should not be empty. + if (attributes.empty()) { + std::string error_message = + "Cannot push data to device with empty arguments."; + LOG(ERROR) << error_message; + error_callback.Run(nfc_error::kInvalidArguments, error_message); + return; + } + + // Create the arguments. + dbus::MethodCall method_call(nfc_device::kNfcDeviceInterface, + nfc_device::kPush); + dbus::MessageWriter writer(&method_call); + dbus::MessageWriter array_writer(NULL); + dbus::MessageWriter dict_entry_writer(NULL); + writer.OpenArray("{sv}", &array_writer); + for (RecordAttributes::const_iterator iter = attributes.begin(); + iter != attributes.end(); ++iter) { + array_writer.OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString(iter->first); + dict_entry_writer.AppendVariantOfString(iter->second); + array_writer.CloseContainer(&dict_entry_writer); + } + writer.CloseContainer(&array_writer); + + object_proxy->CallMethodWithErrorCallback( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&nfc_client_helpers::OnSuccess, callback), + base::Bind(&nfc_client_helpers::OnError, error_callback)); + } + + protected: + // DBusClient override. + virtual void Init(dbus::Bus* bus) OVERRIDE { + VLOG(1) << "Creating NfcDeviceClientImpl"; + DCHECK(bus); + bus_ = bus; + object_map_.reset(new DBusObjectMap( + nfc_device::kNfcDeviceServiceName, this, bus)); + DCHECK(adapter_client_); + adapter_client_->AddObserver(this); + } + + // NfcAdapterClient::Observer override. + virtual void AdapterPropertyChanged( + const dbus::ObjectPath& object_path, + const std::string& property_name) OVERRIDE { + DCHECK(adapter_client_); + NfcAdapterClient::Properties *adapter_properties = + adapter_client_->GetProperties(object_path); + + // Ignore changes to properties other than "Devices". + if (property_name != adapter_properties->devices.name()) + return; + + VLOG(1) << "NFC devices changed."; + + // Add all the new devices. + const ObjectPathVector& received_devices = + adapter_properties->devices.value(); + for (ObjectPathVector::const_iterator iter = received_devices.begin(); + iter != received_devices.end(); ++iter) { + const dbus::ObjectPath &device_path = *iter; + if (object_map_->AddObject(device_path)) { + VLOG(1) << "Found NFC device: " << device_path.value(); + FOR_EACH_OBSERVER(NfcDeviceClient::Observer, observers_, + DeviceFound(device_path, object_path)); + } + } + + // Remove all devices that were lost. + const DBusObjectMap::ObjectMap& known_devices = + object_map_->object_map(); + std::set devices_set(received_devices.begin(), + received_devices.end()); + DBusObjectMap::ObjectMap::const_iterator iter = known_devices.begin(); + while (iter != known_devices.end()) { + // Make a copy here, as the iterator will be invalidated by + // DBusObjectMap::RemoveObject below, but |device_path| is needed to + // notify observers right after. We want to make sure that we notify + // the observers AFTER we remove the object, so that method calls + // to the removed object paths in observer implementations fail + // gracefully. + dbus::ObjectPath device_path = iter->first; + ++iter; + if (!ContainsKey(devices_set, device_path)) { + VLOG(1) << "Lost NFC device: " << device_path.value(); + object_map_->RemoveObject(device_path); + FOR_EACH_OBSERVER(NfcDeviceClient::Observer, observers_, + DeviceLost(device_path, object_path)); + } + } + } + + // nfc_client_helpers::DBusObjectMap::Delegate override. + virtual NfcPropertySet* CreateProperties( + dbus::ObjectProxy* object_proxy) OVERRIDE { + return new Properties( + object_proxy, + base::Bind(&NfcDeviceClientImpl::OnPropertyChanged, + weak_ptr_factory_.GetWeakPtr(), + object_proxy->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) << "Device property changed; Path: " << object_path.value() + << " Property: " << property_name; + FOR_EACH_OBSERVER(NfcDeviceClient::Observer, observers_, + DevicePropertyChanged(object_path, property_name)); + } + + private: + // We maintain a pointer to the bus to be able to request proxies for + // new NFC devices that appear. + dbus::Bus* bus_; + + // Mapping from object paths to object proxies and properties structures that + // were already created by us. + scoped_ptr object_map_; + + // The manager client that we listen to events notifications from. + NfcAdapterClient* adapter_client_; + + // List of observers interested in event notifications. + ObserverList observers_; + + // 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(NfcDeviceClientImpl); +}; + +NfcDeviceClient::NfcDeviceClient() { +} + +NfcDeviceClient::~NfcDeviceClient() { +} + +NfcDeviceClient* NfcDeviceClient::Create(DBusClientImplementationType type, + NfcAdapterClient* adapter_client) { + if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) + return new NfcDeviceClientImpl(adapter_client); + DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); + return new FakeNfcDeviceClient(); +} + +} // namespace chromeos diff --git a/chromeos/dbus/nfc_device_client.h b/chromeos/dbus/nfc_device_client.h new file mode 100644 index 0000000..bbabf7e --- /dev/null +++ b/chromeos/dbus/nfc_device_client.h @@ -0,0 +1,119 @@ +// 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. + +#ifndef CHROMEOS_DBUS_NFC_DEVICE_CLIENT_H_ +#define CHROMEOS_DBUS_NFC_DEVICE_CLIENT_H_ + +#include +#include +#include + +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/dbus_client.h" +#include "chromeos/dbus/dbus_client_implementation_type.h" +#include "chromeos/dbus/nfc_client_helpers.h" +#include "chromeos/dbus/nfc_property_set.h" +#include "dbus/object_path.h" +#include "dbus/object_proxy.h" +#include "dbus/property.h" + +namespace chromeos { + +class NfcAdapterClient; + +// NfcDeviceClient is used to communicate with objects representing remote NFC +// adapters that can be communicated with. +class CHROMEOS_EXPORT NfcDeviceClient : public DBusClient { + public: + // Structure of properties associated with an NFC device. + struct Properties : public NfcPropertySet { + // List of object paths for NDEF records associated with the NFC device. + dbus::Property > records; + + Properties(dbus::ObjectProxy* object_proxy, + const PropertyChangedCallback& callback); + virtual ~Properties(); + }; + + // Interface for observing changes from a remote NFC device. + class Observer { + public: + virtual ~Observer() {} + + // Called when a remote NFC device with the object |object_path| is added + // to the set of known devices associated with the adapter with object path + // |adapter_path|. + virtual void DeviceFound(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& adapter_path) {} + + // Called when a remote NFC device with the object path |object_path| is + // removed from the set of known devices associated with the adapter with + // object path |adapter_path|. + virtual void DeviceLost(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& adapter_path) {} + + // Called when the device property with the name |property_name| on device + // with object path |object_path| has acquired a new value. + virtual void DevicePropertyChanged(const dbus::ObjectPath& object_path, + const std::string& property_name) {} + }; + + // TODO(armansito): Move this typedef to the NFC Record client, once + // implemented. + typedef std::map RecordAttributes; + + virtual ~NfcDeviceClient(); + + // Adds and removes observers for events on all remote NFC devices. Check the + // |object_path| parameter of observer methods to determine which device is + // issuing the event. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + + // Obtain the properties for the NFC device with object path |object_path|; + // any values should be copied if needed. + virtual Properties* GetProperties(const dbus::ObjectPath& object_path) = 0; + + // Creates an NDEF record for the NFC device with object path |object_path| + // using the parameters in |attributes|. |attributes| is a dictionary, + // containing the NFC Record properties which will be assigned to the + // resulting record object and pushed to the device. The properties are + // defined by the NFC Record interface (see namespace "nfc_record" in + // third_party/cros_system_api/dbus/service_constants.h and + // NfcRecordClient::Properties). |attributes| should at least contain a + // "Type" plus any other properties associated with that type. For example: + // + // { + // "Type": "Text", + // "Encoding": "UTF-8", + // "Language": "en", + // "Representation": "Chrome OS rulez!" + // }, + // { + // "Type": "URI", + // "URI": "http://www.chromium.org" + // }, + // etc. + virtual void Push( + const dbus::ObjectPath& object_path, + const RecordAttributes& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) = 0; + + // Creates the instance. + static NfcDeviceClient* Create(DBusClientImplementationType type, + NfcAdapterClient* adapter_client); + + protected: + friend class NfcClientTest; + + NfcDeviceClient(); + + private: + DISALLOW_COPY_AND_ASSIGN(NfcDeviceClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_NFC_DEVICE_CLIENT_H_ diff --git a/chromeos/dbus/nfc_tag_client.cc b/chromeos/dbus/nfc_tag_client.cc new file mode 100644 index 0000000..37f3c0a --- /dev/null +++ b/chromeos/dbus/nfc_tag_client.cc @@ -0,0 +1,250 @@ +// 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_tag_client.h" + +#include + +#include "base/bind.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "chromeos/dbus/fake_nfc_tag_client.h" +#include "chromeos/dbus/nfc_adapter_client.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +using chromeos::nfc_client_helpers::DBusObjectMap; + +namespace chromeos { + +namespace { + +typedef std::vector ObjectPathVector; + +} // namespace + +NfcTagClient::Properties::Properties( + dbus::ObjectProxy* object_proxy, + const PropertyChangedCallback& callback) + : NfcPropertySet(object_proxy, + nfc_tag::kNfcTagInterface, + callback) { + RegisterProperty(nfc_tag::kTypeProperty, &type); + RegisterProperty(nfc_tag::kProtocolProperty, &protocol); + RegisterProperty(nfc_tag::kRecordsProperty, &records); + RegisterProperty(nfc_tag::kReadOnlyProperty, &read_only); +} + +NfcTagClient::Properties::~Properties() { +} + +// The NfcTagClient implementation used in production. +class NfcTagClientImpl : public NfcTagClient, + public NfcAdapterClient::Observer, + public nfc_client_helpers::DBusObjectMap::Delegate { + public: + explicit NfcTagClientImpl(NfcAdapterClient* adapter_client) + : bus_(NULL), + adapter_client_(adapter_client), + weak_ptr_factory_(this) { + DCHECK(adapter_client); + } + + virtual ~NfcTagClientImpl() { + adapter_client_->RemoveObserver(this); + } + + // NfcTagClient override. + virtual void AddObserver(NfcTagClient::Observer* observer) OVERRIDE { + DCHECK(observer); + observers_.AddObserver(observer); + } + + // NfcTagClient override. + virtual void RemoveObserver(NfcTagClient::Observer* observer) OVERRIDE { + DCHECK(observer); + observers_.RemoveObserver(observer); + } + + // NfcTagClient override. + virtual Properties* GetProperties(const dbus::ObjectPath& object_path) + OVERRIDE { + return static_cast( + object_map_->GetObjectProperties(object_path)); + } + + // NfcTagClient override. + virtual void Write( + const dbus::ObjectPath& object_path, + const RecordAttributes& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE { + dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path); + if (!object_proxy) { + std::string error_message = + base::StringPrintf("NFC tag with object path \"%s\" does not exist.", + object_path.value().c_str()); + LOG(ERROR) << error_message; + error_callback.Run(nfc_client_helpers::kUnknownObjectError, + error_message); + return; + } + + // |attributes| should not be empty. + if (attributes.empty()) { + std::string error_message = + "Cannot write data to tag with empty arguments."; + LOG(ERROR) << error_message; + error_callback.Run(nfc_error::kInvalidArguments, error_message); + return; + } + + // Create the arguments. + dbus::MethodCall method_call(nfc_tag::kNfcTagInterface, nfc_tag::kWrite); + dbus::MessageWriter writer(&method_call); + dbus::MessageWriter array_writer(NULL); + dbus::MessageWriter dict_entry_writer(NULL); + writer.OpenArray("{sv}", &array_writer); + for (RecordAttributes::const_iterator iter = attributes.begin(); + iter != attributes.end(); ++iter) { + array_writer.OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString(iter->first); + dict_entry_writer.AppendVariantOfString(iter->second); + array_writer.CloseContainer(&dict_entry_writer); + } + writer.CloseContainer(&array_writer); + + object_proxy->CallMethodWithErrorCallback( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&nfc_client_helpers::OnSuccess, callback), + base::Bind(&nfc_client_helpers::OnError, error_callback)); + } + + protected: + // DBusClient override. + virtual void Init(dbus::Bus* bus) OVERRIDE { + VLOG(1) << "Creating NfcTagClientImpl"; + DCHECK(bus); + bus_ = bus; + object_map_.reset(new nfc_client_helpers::DBusObjectMap( + nfc_tag::kNfcTagServiceName, this, bus)); + DCHECK(adapter_client_); + adapter_client_->AddObserver(this); + } + + private: + // NfcAdapterClient::Observer override. + virtual void AdapterPropertyChanged( + const dbus::ObjectPath& object_path, + const std::string& property_name) OVERRIDE { + // Update the tag proxies. + DCHECK(adapter_client_); + NfcAdapterClient::Properties *adapter_properties = + adapter_client_->GetProperties(object_path); + + // Ignore changes to properties other than "Tags". + if (property_name != adapter_properties->tags.name()) + return; + + VLOG(1) << "NFC tags changed."; + + // Add all the new tags. + const ObjectPathVector& received_tags = + adapter_properties->tags.value(); + for (ObjectPathVector::const_iterator iter = received_tags.begin(); + iter != received_tags.end(); ++iter) { + const dbus::ObjectPath &tag_path = *iter; + if (object_map_->AddObject(tag_path)) { + VLOG(1) << "Found NFC tag: " << tag_path.value(); + FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, + TagFound(tag_path, object_path)); + } + } + + // Remove all tags that were lost. + const DBusObjectMap::ObjectMap& known_tags = + object_map_->object_map(); + std::set tags_set(received_tags.begin(), + received_tags.end()); + DBusObjectMap::ObjectMap::const_iterator iter = known_tags.begin(); + while (iter != known_tags.end()) { + // Make a copy here, as the iterator will be invalidated by + // DBusObjectMap::RemoveObject below, but |device_path| is needed to + // notify observers right after. We want to make sure that we notify + // the observers AFTER we remove the object, so that method calls + // to the removed object paths in observer implementations fail + // gracefully. + dbus::ObjectPath tag_path = iter->first; + ++iter; + if (!ContainsKey(tags_set, tag_path)) { + VLOG(1) << "Lost NFC tag: " << tag_path.value(); + object_map_->RemoveObject(tag_path); + FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, + TagLost(tag_path, object_path)); + } + } + } + + // nfc_client_helpers::DBusObjectMap::Delegate override. + virtual NfcPropertySet* CreateProperties( + dbus::ObjectProxy* object_proxy) OVERRIDE { + return new Properties( + object_proxy, + base::Bind(&NfcTagClientImpl::OnPropertyChanged, + weak_ptr_factory_.GetWeakPtr(), + object_proxy->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) << "Tag property changed; Path: " << object_path.value() + << " Property: " << property_name; + FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, + TagPropertyChanged(object_path, property_name)); + } + + // We maintain a pointer to the bus to be able to request proxies for + // new NFC tags that appear. + dbus::Bus* bus_; + + // Mapping from object paths to object proxies and properties structures that + // were already created by us. + scoped_ptr object_map_; + + // The manager client that we listen to events notifications from. + NfcAdapterClient* adapter_client_; + + // List of observers interested in event notifications. + ObserverList observers_; + + // 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(NfcTagClientImpl); +}; + +NfcTagClient::NfcTagClient() { +} + +NfcTagClient::~NfcTagClient() { +} + +NfcTagClient* NfcTagClient::Create(DBusClientImplementationType type, + NfcAdapterClient* adapter_client) { + if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) + return new NfcTagClientImpl(adapter_client); + DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); + return new FakeNfcTagClient(); +} + +} // namespace chromeos diff --git a/chromeos/dbus/nfc_tag_client.h b/chromeos/dbus/nfc_tag_client.h new file mode 100644 index 0000000..5d7e1e0 --- /dev/null +++ b/chromeos/dbus/nfc_tag_client.h @@ -0,0 +1,130 @@ +// 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. + +#ifndef CHROMEOS_DBUS_NFC_TAG_CLIENT_H_ +#define CHROMEOS_DBUS_NFC_TAG_CLIENT_H_ + +#include +#include +#include + +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/dbus_client.h" +#include "chromeos/dbus/dbus_client_implementation_type.h" +#include "chromeos/dbus/nfc_client_helpers.h" +#include "chromeos/dbus/nfc_property_set.h" +#include "dbus/object_path.h" +#include "dbus/object_proxy.h" +#include "dbus/property.h" + +namespace chromeos { + +class NfcAdapterClient; + +// NfcTagClient is used to communicate with objects representing remote NFC +// tags. +class CHROMEOS_EXPORT NfcTagClient : public DBusClient { + public: + // Structure of properties associated with an NFC tag. + struct Properties : public NfcPropertySet { + // The NFC tag type. Possible values are "Type 1", "Type 2", "Type 3", + // and "Type 4". + dbus::Property type; + + // The NFC tag radio protocol. Possible values are "Felica", "MIFARE", + // "Jewel", "ISO-DEP", and "NFC-DEP". + dbus::Property protocol; + + // List of object paths for NDEF Records associated with the NFC tag. + dbus::Property > records; + + // The current status of the tag's read mode. + dbus::Property read_only; + + Properties(dbus::ObjectProxy* object_proxy, + const PropertyChangedCallback& callback); + virtual ~Properties(); + }; + + // Interface for observing changes from a remote NFC tag. + class Observer { + public: + virtual ~Observer() {} + + // Called when a remote NFC tag with the object path |object_path| is added + // to the set of known tags associated with the adapter with object path + // |adapter_path|. + virtual void TagFound(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& adapter_path) {} + + // Called when a remote NFC tag with the object path |object_path| is + // removed from the set of known tags associated with the adapter with the + // object path |adapter_path|. + virtual void TagLost(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& adapter_path) {} + + // Called when the tag property with the name |property_name| on tag with + // object path |object_path| has acquired a new value. + virtual void TagPropertyChanged(const dbus::ObjectPath& object_path, + const std::string& property_name) {} + }; + + // TODO(armansito): Move this typedef to the NFC Record client, once + // implemented. + typedef std::map RecordAttributes; + + virtual ~NfcTagClient(); + + // Adds and removes observers for events on all remote NFC tags. Check the + // |object_path| parameter of observer methods to determine which tag is + // issuing the event. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + + // Obtain the properties for the NFC tag with object path |object_path|; any + // values should be copied if needed. + virtual Properties* GetProperties(const dbus::ObjectPath& object_path) = 0; + + // Creates an NDEF record for the NFC tag with object path |object_path| + // using the parameters in |attributes|. |attributes| is a dictionary, + // containing the NFC Record properties which will be assigned to the + // resulting record object and written to the tag. The properties are defined + // by the NFC Record interface (see namespace "nfc_record" in + // third_party/cros_system_api/dbus/service_constants.h and + // NfcRecordClient::Properties). |attributes| should at least contain a + // "Type" plus any other properties associated with that type. For example: + // + // { + // "Type": "Text", + // "Encoding": "UTF-8", + // "Language": "en", + // "Representation": "Chrome OS rulez!" + // }, + // { + // "Type": "URI", + // "URI": "http://www.chromium.org" + // }, + // etc. + virtual void Write( + const dbus::ObjectPath& object_path, + const RecordAttributes& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) = 0; + + // Creates the instance. + static NfcTagClient* Create(DBusClientImplementationType type, + NfcAdapterClient* adapter_client); + + protected: + friend class NfcClientTest; + + NfcTagClient(); + + private: + DISALLOW_COPY_AND_ASSIGN(NfcTagClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_NFC_TAG_CLIENT_H_ -- cgit v1.1