diff options
author | rkc <rkc@chromium.org> | 2015-04-16 12:27:24 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-16 19:27:47 +0000 |
commit | 3c011dd0a4d682397b7a1f3c9b786db68d7e967b (patch) | |
tree | f161667621239b426e3212fd07177a0e05e46010 | |
parent | 04ab34e0e1833a71258962285ab1649eae951e0c (diff) | |
download | chromium_src-3c011dd0a4d682397b7a1f3c9b786db68d7e967b.zip chromium_src-3c011dd0a4d682397b7a1f3c9b786db68d7e967b.tar.gz chromium_src-3c011dd0a4d682397b7a1f3c9b786db68d7e967b.tar.bz2 |
Add DBus bindings for BLE Advertisement.
This CL adds the DBus bindings needed to be able to host BLE advertisment
objects and register those advertisements with BlueZ.
R=armansito@chromium.org, jamuraa@chromium.org
BUG=466375
Review URL: https://codereview.chromium.org/1052363005
Cr-Commit-Position: refs/heads/master@{#325497}
-rw-r--r-- | chromeos/chromeos.gyp | 8 | ||||
-rw-r--r-- | chromeos/dbus/bluetooth_le_advertisement_service_provider.cc | 414 | ||||
-rw-r--r-- | chromeos/dbus/bluetooth_le_advertisement_service_provider.h | 76 | ||||
-rw-r--r-- | chromeos/dbus/bluetooth_le_advertising_manager_client.cc | 187 | ||||
-rw-r--r-- | chromeos/dbus/bluetooth_le_advertising_manager_client.h | 83 | ||||
-rw-r--r-- | chromeos/dbus/dbus_client_bundle.cc | 6 | ||||
-rw-r--r-- | chromeos/dbus/dbus_client_bundle.h | 8 | ||||
-rw-r--r-- | chromeos/dbus/dbus_thread_manager.cc | 12 | ||||
-rw-r--r-- | chromeos/dbus/dbus_thread_manager.h | 4 | ||||
-rw-r--r-- | chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.cc | 45 | ||||
-rw-r--r-- | chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.h | 52 | ||||
-rw-r--r-- | chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc | 107 | ||||
-rw-r--r-- | chromeos/dbus/fake_bluetooth_le_advertising_manager_client.h | 79 |
13 files changed, 1081 insertions, 0 deletions
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 41a30f8..a5df534 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -61,6 +61,10 @@ 'dbus/blocking_method_caller.h', 'dbus/bluetooth_adapter_client.cc', 'dbus/bluetooth_adapter_client.h', + 'dbus/bluetooth_le_advertising_manager_client.cc', + 'dbus/bluetooth_le_advertising_manager_client.h', + 'dbus/bluetooth_le_advertisement_service_provider.cc', + 'dbus/bluetooth_le_advertisement_service_provider.h', 'dbus/bluetooth_agent_manager_client.cc', 'dbus/bluetooth_agent_manager_client.h', 'dbus/bluetooth_agent_service_provider.cc', @@ -118,6 +122,10 @@ 'dbus/fake_audio_dsp_client.h', 'dbus/fake_bluetooth_adapter_client.cc', 'dbus/fake_bluetooth_adapter_client.h', + 'dbus/fake_bluetooth_le_advertising_manager_client.cc', + 'dbus/fake_bluetooth_le_advertising_manager_client.h', + 'dbus/fake_bluetooth_le_advertisement_service_provider.cc', + 'dbus/fake_bluetooth_le_advertisement_service_provider.h', 'dbus/fake_bluetooth_agent_manager_client.cc', 'dbus/fake_bluetooth_agent_manager_client.h', 'dbus/fake_bluetooth_agent_service_provider.cc', diff --git a/chromeos/dbus/bluetooth_le_advertisement_service_provider.cc b/chromeos/dbus/bluetooth_le_advertisement_service_provider.cc new file mode 100644 index 0000000..aa3f234 --- /dev/null +++ b/chromeos/dbus/bluetooth_le_advertisement_service_provider.cc @@ -0,0 +1,414 @@ +// Copyright 2015 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/bluetooth_le_advertisement_service_provider.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/stl_util.h" +#include "base/threading/platform_thread.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.h" +#include "dbus/exported_object.h" +#include "dbus/message.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +namespace { +const char kErrorInvalidArgs[] = "org.freedesktop.DBus.Error.InvalidArgs"; +} // namespace + +// The BluetoothAdvertisementServiceProvider implementation used in production. +class BluetoothAdvertisementServiceProviderImpl + : public BluetoothLEAdvertisementServiceProvider { + public: + BluetoothAdvertisementServiceProviderImpl( + dbus::Bus* bus, + const dbus::ObjectPath& object_path, + Delegate* delegate, + AdvertisementType type, + scoped_ptr<UUIDList> service_uuids, + scoped_ptr<ManufacturerData> manufacturer_data, + scoped_ptr<UUIDList> solicit_uuids, + scoped_ptr<ServiceData> service_data) + : origin_thread_id_(base::PlatformThread::CurrentId()), + bus_(bus), + delegate_(delegate), + object_path_(object_path), + type_(type), + service_uuids_(service_uuids.Pass()), + manufacturer_data_(manufacturer_data.Pass()), + solicit_uuids_(solicit_uuids.Pass()), + service_data_(service_data.Pass()), + weak_ptr_factory_(this) { + DCHECK(bus); + DCHECK(delegate); + + VLOG(1) << "Creating Bluetooth Advertisement: " << object_path_.value(); + + exported_object_ = bus_->GetExportedObject(object_path_); + + // Export Bluetooth Advertisement interface methods. + exported_object_->ExportMethod( + bluetooth_advertisement::kBluetoothAdvertisementIntervace, + bluetooth_advertisement::kRelease, + base::Bind(&BluetoothAdvertisementServiceProviderImpl::Release, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothAdvertisementServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + + // Export dbus property methods. + exported_object_->ExportMethod( + dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGet, + base::Bind(&BluetoothAdvertisementServiceProviderImpl::Get, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothAdvertisementServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + + exported_object_->ExportMethod( + dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGetAll, + base::Bind(&BluetoothAdvertisementServiceProviderImpl::GetAll, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothAdvertisementServiceProviderImpl::OnExported, + weak_ptr_factory_.GetWeakPtr())); + } + + ~BluetoothAdvertisementServiceProviderImpl() override { + VLOG(1) << "Cleaning up Bluetooth Advertisement: " << object_path_.value(); + + // Unregister the object path so we can reuse with a new agent. + bus_->UnregisterExportedObject(object_path_); + } + + private: + // Returns true if the current thread is on the origin thread. + bool OnOriginThread() { + return base::PlatformThread::CurrentId() == origin_thread_id_; + } + + // Called by dbus:: when this advertisement is unregistered from the Bluetooth + // daemon, generally by our request. + void Release(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + DCHECK(OnOriginThread()); + DCHECK(delegate_); + + delegate_->Released(); + } + + // Called by dbus:: when the Bluetooth daemon fetches a single property of + // the descriptor. + void Get(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + VLOG(2) << "BluetoothAdvertisementServiceProvider::Get: " + << object_path_.value(); + DCHECK(OnOriginThread()); + + dbus::MessageReader reader(method_call); + + std::string interface_name; + std::string property_name; + if (!reader.PopString(&interface_name) || + !reader.PopString(&property_name) || reader.HasMoreData()) { + scoped_ptr<dbus::ErrorResponse> error_response = + dbus::ErrorResponse::FromMethodCall(method_call, kErrorInvalidArgs, + "Expected 'ss'."); + response_sender.Run(error_response.Pass()); + return; + } + + // Only the advertisement interface is supported. + if (interface_name != + bluetooth_advertisement::kBluetoothAdvertisementIntervace) { + scoped_ptr<dbus::ErrorResponse> error_response = + dbus::ErrorResponse::FromMethodCall( + method_call, kErrorInvalidArgs, + "No such interface: '" + interface_name + "'."); + response_sender.Run(error_response.Pass()); + return; + } + + scoped_ptr<dbus::Response> response = + dbus::Response::FromMethodCall(method_call); + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter variant_writer(NULL); + + if (property_name == bluetooth_advertisement::kTypeProperty) { + writer.OpenVariant("s", &variant_writer); + if (type_ == ADVERTISEMENT_TYPE_BROADCAST) { + variant_writer.AppendString("broadcast"); + } else { + variant_writer.AppendString("peripheral"); + } + } else if ((property_name == + bluetooth_advertisement::kServiceUUIDsProperty) && + service_uuids_) { + writer.OpenVariant("as", &variant_writer); + variant_writer.AppendArrayOfStrings(*service_uuids_); + } else if ((property_name == + bluetooth_advertisement::kSolicitUUIDsProperty) && + solicit_uuids_) { + writer.OpenVariant("as", &variant_writer); + variant_writer.AppendArrayOfStrings(*solicit_uuids_); + } else if ((property_name == + bluetooth_advertisement::kManufacturerDataProperty) && + manufacturer_data_) { + writer.OpenVariant("o", &variant_writer); + AppendManufacturerDataVariant(&variant_writer); + } else if ((property_name == + bluetooth_advertisement::kServiceDataProperty) && + service_data_) { + writer.OpenVariant("o", &variant_writer); + AppendServiceDataVariant(&variant_writer); + } else { + scoped_ptr<dbus::ErrorResponse> error_response = + dbus::ErrorResponse::FromMethodCall( + method_call, kErrorInvalidArgs, + "No such property: '" + property_name + "'."); + response_sender.Run(error_response.Pass()); + } + + writer.CloseContainer(&variant_writer); + response_sender.Run(response.Pass()); + } + + // Called by dbus:: when the Bluetooth daemon fetches all properties of the + // descriptor. + void GetAll(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + VLOG(2) << "BluetoothAdvertisementServiceProvider::GetAll: " + << object_path_.value(); + DCHECK(OnOriginThread()); + + dbus::MessageReader reader(method_call); + + std::string interface_name; + if (!reader.PopString(&interface_name) || reader.HasMoreData()) { + scoped_ptr<dbus::ErrorResponse> error_response = + dbus::ErrorResponse::FromMethodCall(method_call, kErrorInvalidArgs, + "Expected 's'."); + response_sender.Run(error_response.Pass()); + return; + } + + // Only the advertisement interface is supported. + if (interface_name != + bluetooth_advertisement::kBluetoothAdvertisementIntervace) { + scoped_ptr<dbus::ErrorResponse> error_response = + dbus::ErrorResponse::FromMethodCall( + method_call, kErrorInvalidArgs, + "No such interface: '" + interface_name + "'."); + response_sender.Run(error_response.Pass()); + return; + } + + response_sender.Run(CreateGetAllResponse(method_call).Pass()); + } + + // Called by dbus:: when a method is exported. + void OnExported(const std::string& interface_name, + const std::string& method_name, + bool success) { + LOG_IF(WARNING, !success) << "Failed to export " << interface_name << "." + << method_name; + } + + // Helper for populating the DBus response with the advertisement data. + scoped_ptr<dbus::Response> CreateGetAllResponse( + dbus::MethodCall* method_call) { + VLOG(2) << "Descriptor value obtained from delegate. Responding to " + << "GetAll."; + + scoped_ptr<dbus::Response> response = + dbus::Response::FromMethodCall(method_call); + + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter array_writer(NULL); + + writer.OpenArray("{sv}", &array_writer); + + AppendType(&array_writer); + AppendServiceUUIDs(&array_writer); + AppendManufacturerData(&array_writer); + AppendSolicitUUIDs(&array_writer); + AppendServiceData(&array_writer); + + writer.CloseContainer(&array_writer); + return response; + } + + // Called by the Delegate in response to a successful method call to get the + // descriptor value. + void OnGet(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender, + const std::vector<uint8>& value) { + VLOG(2) << "Returning descriptor value obtained from delegate."; + scoped_ptr<dbus::Response> response = + dbus::Response::FromMethodCall(method_call); + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter variant_writer(NULL); + + writer.OpenVariant("ay", &variant_writer); + variant_writer.AppendArrayOfBytes(value.data(), value.size()); + writer.CloseContainer(&variant_writer); + + response_sender.Run(response.Pass()); + } + + void AppendType(dbus::MessageWriter* array_writer) { + dbus::MessageWriter dict_entry_writer(NULL); + array_writer->OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString(bluetooth_advertisement::kTypeProperty); + if (type_ == ADVERTISEMENT_TYPE_BROADCAST) { + dict_entry_writer.AppendString("broadcast"); + } else { + dict_entry_writer.AppendString("peripheral"); + } + array_writer->CloseContainer(&dict_entry_writer); + } + + void AppendServiceUUIDs(dbus::MessageWriter* array_writer) { + dbus::MessageWriter dict_entry_writer(NULL); + array_writer->OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString( + bluetooth_advertisement::kServiceUUIDsProperty); + dict_entry_writer.AppendArrayOfStrings(*service_uuids_); + array_writer->CloseContainer(&dict_entry_writer); + } + + void AppendManufacturerData(dbus::MessageWriter* array_writer) { + dbus::MessageWriter dict_entry_writer(NULL); + array_writer->OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString( + bluetooth_advertisement::kManufacturerDataProperty); + dbus::MessageWriter variant_writer(NULL); + dict_entry_writer.OpenVariant("a{qay}", &variant_writer); + AppendManufacturerDataVariant(&variant_writer); + dict_entry_writer.CloseContainer(&variant_writer); + array_writer->CloseContainer(&dict_entry_writer); + } + + void AppendSolicitUUIDs(dbus::MessageWriter* array_writer) { + dbus::MessageWriter dict_entry_writer(NULL); + array_writer->OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString( + bluetooth_advertisement::kSolicitUUIDsProperty); + dict_entry_writer.AppendArrayOfStrings(*solicit_uuids_); + array_writer->CloseContainer(&dict_entry_writer); + } + + void AppendServiceData(dbus::MessageWriter* array_writer) { + dbus::MessageWriter dict_entry_writer(NULL); + array_writer->OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString( + bluetooth_advertisement::kServiceDataProperty); + dbus::MessageWriter variant_writer(NULL); + dict_entry_writer.OpenVariant("a{say}", &variant_writer); + AppendServiceDataVariant(&variant_writer); + dict_entry_writer.CloseContainer(&variant_writer); + array_writer->CloseContainer(&dict_entry_writer); + } + + void AppendManufacturerDataVariant(dbus::MessageWriter* writer) { + dbus::MessageWriter array_writer(NULL); + writer->OpenArray("{qay}", &array_writer); + for (const auto& m : *manufacturer_data_) { + dbus::MessageWriter entry_writer(NULL); + + array_writer.OpenDictEntry(&entry_writer); + + entry_writer.AppendUint32(m.first); + entry_writer.AppendArrayOfBytes(vector_as_array(&m.second), + m.second.size()); + + array_writer.CloseContainer(&entry_writer); + } + writer->CloseContainer(&array_writer); + } + + void AppendServiceDataVariant(dbus::MessageWriter* writer) { + dbus::MessageWriter array_writer(NULL); + writer->OpenArray("{say}", &array_writer); + for (const auto& m : *service_data_) { + dbus::MessageWriter entry_writer(NULL); + + array_writer.OpenDictEntry(&entry_writer); + + entry_writer.AppendString(m.first); + entry_writer.AppendArrayOfBytes(vector_as_array(&m.second), + m.second.size()); + + array_writer.CloseContainer(&entry_writer); + } + writer->CloseContainer(&array_writer); + } + + // Origin thread (i.e. the UI thread in production). + base::PlatformThreadId origin_thread_id_; + + // D-Bus bus object is exported on, not owned by this object and must + // outlive it. + dbus::Bus* bus_; + + // All incoming method calls are passed on to the Delegate and a callback + // passed to generate the reply. |delegate_| is generally the object that + // owns this one, and must outlive it. + Delegate* delegate_; + + // D-Bus object path of object we are exporting, kept so we can unregister + // again in our destructor. + dbus::ObjectPath object_path_; + + // Advertisement data that needs to be provided to BlueZ when requested. + AdvertisementType type_; + scoped_ptr<UUIDList> service_uuids_; + scoped_ptr<ManufacturerData> manufacturer_data_; + scoped_ptr<UUIDList> solicit_uuids_; + scoped_ptr<ServiceData> service_data_; + + // D-Bus object we are exporting, owned by this object. + scoped_refptr<dbus::ExportedObject> exported_object_; + + // 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<BluetoothAdvertisementServiceProviderImpl> + weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothAdvertisementServiceProviderImpl); +}; + +BluetoothLEAdvertisementServiceProvider:: + BluetoothLEAdvertisementServiceProvider() { +} + +BluetoothLEAdvertisementServiceProvider:: + ~BluetoothLEAdvertisementServiceProvider() { +} + +// static +BluetoothLEAdvertisementServiceProvider* +BluetoothLEAdvertisementServiceProvider::Create( + dbus::Bus* bus, + const dbus::ObjectPath& object_path, + Delegate* delegate, + AdvertisementType type, + scoped_ptr<UUIDList> service_uuids, + scoped_ptr<ManufacturerData> manufacturer_data, + scoped_ptr<UUIDList> solicit_uuids, + scoped_ptr<ServiceData> service_data) { + if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) { + return new BluetoothAdvertisementServiceProviderImpl( + bus, object_path, delegate, type, service_uuids.Pass(), + manufacturer_data.Pass(), solicit_uuids.Pass(), service_data.Pass()); + } else { + return new FakeBluetoothLEAdvertisementServiceProvider(object_path, + delegate); + } +} + +} // namespace chromeos diff --git a/chromeos/dbus/bluetooth_le_advertisement_service_provider.h b/chromeos/dbus/bluetooth_le_advertisement_service_provider.h new file mode 100644 index 0000000..4cea5d8 --- /dev/null +++ b/chromeos/dbus/bluetooth_le_advertisement_service_provider.h @@ -0,0 +1,76 @@ +// Copyright 2015 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_BLUETOOTH_LE_ADVERTISEMENT_SERVICE_PROVIDER_H_ +#define CHROMEOS_DBUS_BLUETOOTH_LE_ADVERTISEMENT_SERVICE_PROVIDER_H_ + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "chromeos/chromeos_export.h" +#include "dbus/bus.h" +#include "dbus/file_descriptor.h" +#include "dbus/object_path.h" + +namespace chromeos { + +// BluetoothAdvertisementServiceProvider is used to provide a D-Bus object that +// the Bluetooth daemon can communicate with to advertise data. +class CHROMEOS_EXPORT BluetoothLEAdvertisementServiceProvider { + public: + using UUIDList = std::vector<std::string>; + using ManufacturerData = std::map<uint16_t, std::vector<uint8_t>>; + using ServiceData = std::map<std::string, std::vector<uint8_t>>; + + // Type of advertisement. + enum AdvertisementType { + ADVERTISEMENT_TYPE_BROADCAST, + ADVERTISEMENT_TYPE_PERIPHERAL + }; + + // Interface for reacting to advertisement changes. + class Delegate { + public: + virtual ~Delegate() {} + + // This method will be called when the advertisement is unregistered from + // the Bluetooth daemon, generally at shutdown or if the adapter goes away. + // It may be used to perform cleanup tasks. This corresponds to the + // org.bluez.LEAdvertisement1.Release method and is renamed to avoid a + // conflict with base::Refcounted<T>. + virtual void Released() = 0; + }; + + virtual ~BluetoothLEAdvertisementServiceProvider(); + + // Creates the instance where |bus| is the D-Bus bus connection to export + // the object onto, |object_path| is the object path that it should have + // and |delegate| is the object to which all method calls will be passed + // and responses generated from. + static BluetoothLEAdvertisementServiceProvider* Create( + dbus::Bus* bus, + const dbus::ObjectPath& object_path, + Delegate* delegate, + AdvertisementType type, + scoped_ptr<UUIDList> service_uuids, + scoped_ptr<ManufacturerData> manufacturer_data, + scoped_ptr<UUIDList> solicit_uuids, + scoped_ptr<ServiceData> service_data); + + protected: + BluetoothLEAdvertisementServiceProvider(); + + private: + DISALLOW_COPY_AND_ASSIGN(BluetoothLEAdvertisementServiceProvider); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_BLUETOOTH_LE_ADVERTISEMENT_SERVICE_PROVIDER_H_ diff --git a/chromeos/dbus/bluetooth_le_advertising_manager_client.cc b/chromeos/dbus/bluetooth_le_advertising_manager_client.cc new file mode 100644 index 0000000..00f4f67 --- /dev/null +++ b/chromeos/dbus/bluetooth_le_advertising_manager_client.cc @@ -0,0 +1,187 @@ +// Copyright 2015 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/bluetooth_le_advertising_manager_client.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/observer_list.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "dbus/object_manager.h" +#include "dbus/object_proxy.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +const char BluetoothLEAdvertisingManagerClient::kNoResponseError[] = + "org.chromium.Error.NoResponse"; + +// The BluetoothAdvertisementManagerClient implementation used in production. +class BluetoothAdvertisementManagerClientImpl + : public BluetoothLEAdvertisingManagerClient, + public dbus::ObjectManager::Interface { + public: + BluetoothAdvertisementManagerClientImpl() + : object_manager_(NULL), weak_ptr_factory_(this) {} + + ~BluetoothAdvertisementManagerClientImpl() override { + object_manager_->UnregisterInterface( + bluetooth_advertising_manager::kBluetoothAdvertisingManagerInterface); + } + + // BluetoothAdapterClient override. + void AddObserver( + BluetoothLEAdvertisingManagerClient::Observer* observer) override { + DCHECK(observer); + observers_.AddObserver(observer); + } + + // BluetoothAdapterClient override. + void RemoveObserver( + BluetoothLEAdvertisingManagerClient::Observer* observer) override { + DCHECK(observer); + observers_.RemoveObserver(observer); + } + + // dbus::ObjectManager::Interface override. + dbus::PropertySet* CreateProperties( + dbus::ObjectProxy* object_proxy, + const dbus::ObjectPath& object_path, + const std::string& interface_name) override { + return new dbus::PropertySet(object_proxy, interface_name, + dbus::PropertySet::PropertyChangedCallback()); + } + + // BluetoothAdvertisementManagerClient override. + void RegisterAdvertisement(const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) override { + dbus::MethodCall method_call( + bluetooth_advertising_manager::kBluetoothAdvertisingManagerInterface, + bluetooth_advertising_manager::kRegisterAdvertisement); + + dbus::MessageWriter writer(&method_call); + writer.AppendObjectPath(advertisement_object_path); + + // Empty dictionary for options. + dbus::MessageWriter dict_entry_writer(NULL); + writer.OpenDictEntry(&dict_entry_writer); + writer.CloseContainer(&dict_entry_writer); + + writer.AppendObjectPath(advertisement_object_path); + + dbus::ObjectProxy* object_proxy = + object_manager_->GetObjectProxy(manager_object_path); + object_proxy->CallMethodWithErrorCallback( + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&BluetoothAdvertisementManagerClientImpl::OnSuccess, + weak_ptr_factory_.GetWeakPtr(), callback), + base::Bind(&BluetoothAdvertisementManagerClientImpl::OnError, + weak_ptr_factory_.GetWeakPtr(), error_callback)); + } + + // BluetoothAdvertisementManagerClient override. + void UnregisterAdvertisement( + const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) override { + dbus::MethodCall method_call( + bluetooth_advertising_manager::kBluetoothAdvertisingManagerInterface, + bluetooth_advertising_manager::kUnregisterAdvertisement); + + dbus::MessageWriter writer(&method_call); + writer.AppendObjectPath(advertisement_object_path); + + dbus::ObjectProxy* object_proxy = + object_manager_->GetObjectProxy(manager_object_path); + object_proxy->CallMethodWithErrorCallback( + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&BluetoothAdvertisementManagerClientImpl::OnSuccess, + weak_ptr_factory_.GetWeakPtr(), callback), + base::Bind(&BluetoothAdvertisementManagerClientImpl::OnError, + weak_ptr_factory_.GetWeakPtr(), error_callback)); + } + + protected: + void Init(dbus::Bus* bus) override { + DCHECK(bus); + object_manager_ = bus->GetObjectManager( + bluetooth_object_manager::kBluetoothObjectManagerServiceName, + dbus::ObjectPath( + bluetooth_object_manager::kBluetoothObjectManagerServicePath)); + object_manager_->RegisterInterface( + bluetooth_advertising_manager::kBluetoothAdvertisingManagerInterface, + this); + } + + private: + // Called by dbus::ObjectManager when an object with the advertising manager + // interface is created. Informs observers. + void ObjectAdded(const dbus::ObjectPath& object_path, + const std::string& interface_name) override { + FOR_EACH_OBSERVER(BluetoothLEAdvertisingManagerClient::Observer, observers_, + AdvertisingManagerAdded(object_path)); + } + + // Called by dbus::ObjectManager when an object with the advertising manager + // interface is removed. Informs observers. + void ObjectRemoved(const dbus::ObjectPath& object_path, + const std::string& interface_name) override { + FOR_EACH_OBSERVER(BluetoothLEAdvertisingManagerClient::Observer, observers_, + AdvertisingManagerRemoved(object_path)); + } + + // Called when a response for successful method call is received. + void OnSuccess(const base::Closure& callback, dbus::Response* response) { + DCHECK(response); + callback.Run(); + } + + // Called when a response for a failed method call is received. + void OnError(const ErrorCallback& error_callback, + dbus::ErrorResponse* response) { + // Error response has optional error message argument. + std::string error_name; + std::string error_message; + if (response) { + dbus::MessageReader reader(response); + error_name = response->GetErrorName(); + reader.PopString(&error_message); + } else { + error_name = kNoResponseError; + error_message = ""; + } + error_callback.Run(error_name, error_message); + } + + dbus::ObjectManager* object_manager_; + + // List of observers interested in event notifications from us. + ObserverList<BluetoothLEAdvertisingManagerClient::Observer> 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<BluetoothAdvertisementManagerClientImpl> + weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothAdvertisementManagerClientImpl); +}; + +BluetoothLEAdvertisingManagerClient::BluetoothLEAdvertisingManagerClient() { +} + +BluetoothLEAdvertisingManagerClient::~BluetoothLEAdvertisingManagerClient() { +} + +BluetoothLEAdvertisingManagerClient* +BluetoothLEAdvertisingManagerClient::Create() { + return new BluetoothAdvertisementManagerClientImpl(); +} + +} // namespace chromeos diff --git a/chromeos/dbus/bluetooth_le_advertising_manager_client.h b/chromeos/dbus/bluetooth_le_advertising_manager_client.h new file mode 100644 index 0000000..5160a9f --- /dev/null +++ b/chromeos/dbus/bluetooth_le_advertising_manager_client.h @@ -0,0 +1,83 @@ +// Copyright 2015 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_BLUETOOTH_LE_ADVERTISING_MANAGER_CLIENT_H_ +#define CHROMEOS_DBUS_BLUETOOTH_LE_ADVERTISING_MANAGER_CLIENT_H_ + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/dbus_client.h" +#include "dbus/object_path.h" + +namespace chromeos { + +// BluetoothAdvertisingManagerClient is used to communicate with the advertising +// manager object of the BlueZ daemon. +class CHROMEOS_EXPORT BluetoothLEAdvertisingManagerClient : public DBusClient { + public: + // Interface for observing changes to advertising managers. + class Observer { + public: + virtual ~Observer() {} + + // Called when an advertising manager with object path |object_path| is + // added to the system. + virtual void AdvertisingManagerAdded(const dbus::ObjectPath& object_path) {} + + // Called when an advertising manager with object path |object_path| is + // removed from the system. + virtual void AdvertisingManagerRemoved( + const dbus::ObjectPath& object_path) {} + }; + + ~BluetoothLEAdvertisingManagerClient() override; + + // Adds and removes observers for events which change the advertising + // managers on the system. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + + // The ErrorCallback is used by advertising manager methods to indicate + // failure. It receives two arguments: the name of the error in |error_name| + // and an optional message in |error_message|. + using ErrorCallback = base::Callback<void(const std::string& error_name, + const std::string& error_message)>; + + // Registers an advertisement with the DBus object path + // |advertisement_object_path| with BlueZ's advertising manager. + virtual void RegisterAdvertisement( + const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) = 0; + + // Unregisters an advertisement with the DBus object path + // |advertisement_object_path| with BlueZ's advertising manager. + virtual void UnregisterAdvertisement( + const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) = 0; + + // Creates the instance. + static BluetoothLEAdvertisingManagerClient* Create(); + + // Constants used to indicate exceptional error conditions. + static const char kNoResponseError[]; + + protected: + BluetoothLEAdvertisingManagerClient(); + + private: + DISALLOW_COPY_AND_ASSIGN(BluetoothLEAdvertisingManagerClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_BLUETOOTH_LE_ADVERTISING_MANAGER_CLIENT_H_ diff --git a/chromeos/dbus/dbus_client_bundle.cc b/chromeos/dbus/dbus_client_bundle.cc index 608f2e3..3296736 100644 --- a/chromeos/dbus/dbus_client_bundle.cc +++ b/chromeos/dbus/dbus_client_bundle.cc @@ -21,6 +21,7 @@ #include "chromeos/dbus/bluetooth_gatt_manager_client.h" #include "chromeos/dbus/bluetooth_gatt_service_client.h" #include "chromeos/dbus/bluetooth_input_client.h" +#include "chromeos/dbus/bluetooth_le_advertising_manager_client.h" #include "chromeos/dbus/bluetooth_media_client.h" #include "chromeos/dbus/bluetooth_media_transport_client.h" #include "chromeos/dbus/bluetooth_profile_manager_client.h" @@ -40,6 +41,7 @@ #include "chromeos/dbus/fake_bluetooth_gatt_manager_client.h" #include "chromeos/dbus/fake_bluetooth_gatt_service_client.h" #include "chromeos/dbus/fake_bluetooth_input_client.h" +#include "chromeos/dbus/fake_bluetooth_le_advertising_manager_client.h" #include "chromeos/dbus/fake_bluetooth_media_client.h" #include "chromeos/dbus/fake_bluetooth_media_transport_client.h" #include "chromeos/dbus/fake_bluetooth_profile_manager_client.h" @@ -161,6 +163,8 @@ DBusClientBundle::DBusClientBundle(DBusClientTypeMask unstub_client_mask) if (!IsUsingStub(BLUETOOTH)) { bluetooth_adapter_client_.reset(BluetoothAdapterClient::Create()); + bluetooth_le_advertising_manager_client_.reset( + BluetoothLEAdvertisingManagerClient::Create()); bluetooth_agent_manager_client_.reset( BluetoothAgentManagerClient::Create()); bluetooth_device_client_.reset(BluetoothDeviceClient::Create()); @@ -180,6 +184,8 @@ DBusClientBundle::DBusClientBundle(DBusClientTypeMask unstub_client_mask) BluetoothGattServiceClient::Create()); } else { bluetooth_adapter_client_.reset(new FakeBluetoothAdapterClient); + bluetooth_le_advertising_manager_client_.reset( + new FakeBluetoothLEAdvertisingManagerClient); bluetooth_agent_manager_client_.reset(new FakeBluetoothAgentManagerClient); bluetooth_device_client_.reset(new FakeBluetoothDeviceClient); bluetooth_input_client_.reset(new FakeBluetoothInputClient); diff --git a/chromeos/dbus/dbus_client_bundle.h b/chromeos/dbus/dbus_client_bundle.h index 2801b4f..6db1953 100644 --- a/chromeos/dbus/dbus_client_bundle.h +++ b/chromeos/dbus/dbus_client_bundle.h @@ -23,6 +23,7 @@ class BluetoothGattDescriptorClient; class BluetoothGattManagerClient; class BluetoothGattServiceClient; class BluetoothInputClient; +class BluetoothLEAdvertisingManagerClient; class BluetoothMediaClient; class BluetoothMediaTransportClient; class BluetoothProfileManagerClient; @@ -123,6 +124,11 @@ class CHROMEOS_EXPORT DBusClientBundle { return bluetooth_adapter_client_.get(); } + BluetoothLEAdvertisingManagerClient* + bluetooth_le_advertising_manager_client() { + return bluetooth_le_advertising_manager_client_.get(); + } + BluetoothAgentManagerClient* bluetooth_agent_manager_client() { return bluetooth_agent_manager_client_.get(); } @@ -296,6 +302,8 @@ class CHROMEOS_EXPORT DBusClientBundle { scoped_ptr<ApManagerClient> ap_manager_client_; scoped_ptr<AudioDspClient> audio_dsp_client_; scoped_ptr<BluetoothAdapterClient> bluetooth_adapter_client_; + scoped_ptr<BluetoothLEAdvertisingManagerClient> + bluetooth_le_advertising_manager_client_; scoped_ptr<BluetoothAgentManagerClient> bluetooth_agent_manager_client_; scoped_ptr<BluetoothDeviceClient> bluetooth_device_client_; scoped_ptr<BluetoothGattCharacteristicClient> diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc index 6db36c2..3f55270 100644 --- a/chromeos/dbus/dbus_thread_manager.cc +++ b/chromeos/dbus/dbus_thread_manager.cc @@ -19,6 +19,7 @@ #include "chromeos/dbus/bluetooth_gatt_manager_client.h" #include "chromeos/dbus/bluetooth_gatt_service_client.h" #include "chromeos/dbus/bluetooth_input_client.h" +#include "chromeos/dbus/bluetooth_le_advertising_manager_client.h" #include "chromeos/dbus/bluetooth_media_client.h" #include "chromeos/dbus/bluetooth_media_transport_client.h" #include "chromeos/dbus/bluetooth_profile_manager_client.h" @@ -132,6 +133,11 @@ BluetoothAdapterClient* DBusThreadManager::GetBluetoothAdapterClient() { return client_bundle_->bluetooth_adapter_client(); } +BluetoothLEAdvertisingManagerClient* +DBusThreadManager::GetBluetoothLEAdvertisingManagerClient() { + return client_bundle_->bluetooth_le_advertising_manager_client(); +} + BluetoothAgentManagerClient* DBusThreadManager::GetBluetoothAgentManagerClient() { return client_bundle_->bluetooth_agent_manager_client(); @@ -488,6 +494,12 @@ void DBusThreadManagerSetter::SetBluetoothAdapterClient( client.Pass(); } +void DBusThreadManagerSetter::SetBluetoothLEAdvertisingManagerClient( + scoped_ptr<BluetoothLEAdvertisingManagerClient> client) { + DBusThreadManager::Get()->client_bundle_-> + bluetooth_le_advertising_manager_client_ = client.Pass(); +} + void DBusThreadManagerSetter::SetBluetoothAgentManagerClient( scoped_ptr<BluetoothAgentManagerClient> client) { DBusThreadManager::Get()->client_bundle_->bluetooth_agent_manager_client_ = diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h index 26d5f86..408d846 100644 --- a/chromeos/dbus/dbus_thread_manager.h +++ b/chromeos/dbus/dbus_thread_manager.h @@ -29,6 +29,7 @@ class AmplifierClient; class ApManagerClient; class AudioDspClient; class BluetoothAdapterClient; +class BluetoothLEAdvertisingManagerClient; class BluetoothAgentManagerClient; class BluetoothDeviceClient; class BluetoothGattCharacteristicClient; @@ -126,6 +127,7 @@ class CHROMEOS_EXPORT DBusThreadManager { ApManagerClient* GetApManagerClient(); AudioDspClient* GetAudioDspClient(); BluetoothAdapterClient* GetBluetoothAdapterClient(); + BluetoothLEAdvertisingManagerClient* GetBluetoothLEAdvertisingManagerClient(); BluetoothAgentManagerClient* GetBluetoothAgentManagerClient(); BluetoothDeviceClient* GetBluetoothDeviceClient(); BluetoothGattCharacteristicClient* GetBluetoothGattCharacteristicClient(); @@ -213,6 +215,8 @@ class CHROMEOS_EXPORT DBusThreadManagerSetter { void SetAmplifierClient(scoped_ptr<AmplifierClient> client); void SetAudioDspClient(scoped_ptr<AudioDspClient> client); void SetBluetoothAdapterClient(scoped_ptr<BluetoothAdapterClient> client); + void SetBluetoothLEAdvertisingManagerClient( + scoped_ptr<BluetoothLEAdvertisingManagerClient> client); void SetBluetoothAgentManagerClient( scoped_ptr<BluetoothAgentManagerClient> client); void SetBluetoothDeviceClient(scoped_ptr<BluetoothDeviceClient> client); diff --git a/chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.cc b/chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.cc new file mode 100644 index 0000000..24bfb4f --- /dev/null +++ b/chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.cc @@ -0,0 +1,45 @@ +// Copyright 2015 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/dbus_thread_manager.h" +#include "fake_bluetooth_le_advertisement_service_provider.h" +#include "fake_bluetooth_le_advertising_manager_client.h" + +namespace chromeos { + +FakeBluetoothLEAdvertisementServiceProvider:: + FakeBluetoothLEAdvertisementServiceProvider( + const dbus::ObjectPath& object_path, + Delegate* delegate) + : object_path_(object_path), delegate_(delegate) { + VLOG(1) << "Creating Bluetooth Advertisement: " << object_path_.value(); + + FakeBluetoothLEAdvertisingManagerClient* + fake_bluetooth_profile_manager_client = + static_cast<FakeBluetoothLEAdvertisingManagerClient*>( + DBusThreadManager::Get() + ->GetBluetoothLEAdvertisingManagerClient()); + fake_bluetooth_profile_manager_client->RegisterAdvertisementServiceProvider( + this); +} + +FakeBluetoothLEAdvertisementServiceProvider:: + ~FakeBluetoothLEAdvertisementServiceProvider() { + VLOG(1) << "Cleaning up Bluetooth Advertisement: " << object_path_.value(); + + FakeBluetoothLEAdvertisingManagerClient* + fake_bluetooth_profile_manager_client = + static_cast<FakeBluetoothLEAdvertisingManagerClient*>( + DBusThreadManager::Get() + ->GetBluetoothLEAdvertisingManagerClient()); + fake_bluetooth_profile_manager_client->UnregisterAdvertisementServiceProvider( + this); +} + +void FakeBluetoothLEAdvertisementServiceProvider::Release() { + VLOG(1) << object_path_.value() << ": Release"; + delegate_->Released(); +} + +} // namespace chromeos diff --git a/chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.h b/chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.h new file mode 100644 index 0000000..c56abb4 --- /dev/null +++ b/chromeos/dbus/fake_bluetooth_le_advertisement_service_provider.h @@ -0,0 +1,52 @@ +// Copyright 2015 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_BLUETOOTH_LE_ADVERTISEMENT_SERVICE_PROVIDER_H_ +#define CHROMEOS_DBUS_FAKE_BLUETOOTH_LE_ADVERTISEMENT_SERVICE_PROVIDER_H_ + +#include "base/bind.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/bluetooth_le_advertisement_service_provider.h" +#include "dbus/file_descriptor.h" +#include "dbus/object_path.h" + +namespace chromeos { + +// FakeBluetoothAdvertisementServiceProvider simulates the behavior of a local +// Bluetooth agent object and is used both in test cases in place of a +// mock and on the Linux desktop. +class CHROMEOS_EXPORT FakeBluetoothLEAdvertisementServiceProvider + : public BluetoothLEAdvertisementServiceProvider { + public: + FakeBluetoothLEAdvertisementServiceProvider( + const dbus::ObjectPath& object_path, + Delegate* delegate); + ~FakeBluetoothLEAdvertisementServiceProvider() override; + + // Each of these calls the equivalent + // BluetoothAdvertisementServiceProvider::Delegate method on the object passed + // on construction. + void Release(); + + const dbus::ObjectPath& object_path() { return object_path_; } + + private: + friend class FakeBluetoothLEAdvertisingManagerClient; + + // D-Bus object path we are faking. + dbus::ObjectPath object_path_; + + // All incoming method calls are passed on to the Delegate and a callback + // passed to generate the reply. |delegate_| is generally the object that + // owns this one, and must outlive it. + Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEAdvertisementServiceProvider); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_FAKE_BLUETOOTH_LE_ADVERTISEMENT_SERVICE_PROVIDER_H_ diff --git a/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc b/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc new file mode 100644 index 0000000..8145d1c --- /dev/null +++ b/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc @@ -0,0 +1,107 @@ +// Copyright 2015 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 "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "dbus/object_proxy.h" +#include "fake_bluetooth_le_advertisement_service_provider.h" +#include "fake_bluetooth_le_advertising_manager_client.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +const char FakeBluetoothLEAdvertisingManagerClient::kAdvertisingManagerPath[] = + "/fake/hci0"; + +FakeBluetoothLEAdvertisingManagerClient:: + FakeBluetoothLEAdvertisingManagerClient() { +} + +FakeBluetoothLEAdvertisingManagerClient:: + ~FakeBluetoothLEAdvertisingManagerClient() { +} + +void FakeBluetoothLEAdvertisingManagerClient::Init(dbus::Bus* bus) { +} + +void FakeBluetoothLEAdvertisingManagerClient::AddObserver(Observer* observer) { +} + +void FakeBluetoothLEAdvertisingManagerClient::RemoveObserver( + Observer* observer) { +} + +void FakeBluetoothLEAdvertisingManagerClient::RegisterAdvertisement( + const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) { + VLOG(1) << "RegisterAdvertisment: " << advertisement_object_path.value(); + + if (manager_object_path != dbus::ObjectPath(kAdvertisingManagerPath)) { + error_callback.Run(kNoResponseError, "Invalid Advertising Manager path."); + return; + } + + ServiceProviderMap::iterator iter = + service_provider_map_.find(advertisement_object_path); + if (iter == service_provider_map_.end()) { + error_callback.Run(bluetooth_advertising_manager::kErrorInvalidArguments, + "Advertisement object not registered"); + } else if (!currently_registered_.value().empty()) { + error_callback.Run(bluetooth_advertising_manager::kErrorFailed, + "Maximum advertisements reached"); + } else if (advertisement_object_path != currently_registered_) { + error_callback.Run(bluetooth_advertising_manager::kErrorAlreadyExists, + "Already advertising."); + } else { + currently_registered_ = advertisement_object_path; + base::MessageLoop::current()->PostTask(FROM_HERE, callback); + } +} + +void FakeBluetoothLEAdvertisingManagerClient::UnregisterAdvertisement( + const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) { + VLOG(1) << "UnregisterAdvertisment: " << advertisement_object_path.value(); + + if (manager_object_path != dbus::ObjectPath(kAdvertisingManagerPath)) { + error_callback.Run(kNoResponseError, "Invalid Advertising Manager path."); + return; + } + + ServiceProviderMap::iterator iter = + service_provider_map_.find(advertisement_object_path); + if (iter == service_provider_map_.end()) { + error_callback.Run(bluetooth_advertising_manager::kErrorDoesNotExist, + "Advertisement not registered"); + } else if (advertisement_object_path != currently_registered_) { + error_callback.Run(bluetooth_advertising_manager::kErrorDoesNotExist, + "Does not exist"); + } else { + currently_registered_ = dbus::ObjectPath(""); + base::MessageLoop::current()->PostTask(FROM_HERE, callback); + } +} + +void FakeBluetoothLEAdvertisingManagerClient:: + RegisterAdvertisementServiceProvider( + FakeBluetoothLEAdvertisementServiceProvider* service_provider) { + service_provider_map_[service_provider->object_path_] = service_provider; +} + +void FakeBluetoothLEAdvertisingManagerClient:: + UnregisterAdvertisementServiceProvider( + FakeBluetoothLEAdvertisementServiceProvider* service_provider) { + ServiceProviderMap::iterator iter = + service_provider_map_.find(service_provider->object_path_); + if (iter != service_provider_map_.end() && iter->second == service_provider) + service_provider_map_.erase(iter); +} + +} // namespace chromeos diff --git a/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.h b/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.h new file mode 100644 index 0000000..ff340e8 --- /dev/null +++ b/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.h @@ -0,0 +1,79 @@ +// Copyright 2015 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_BLUETOOTH_LE_ADVERTISING_MANAGER_CLIENT_H_ +#define CHROMEOS_DBUS_FAKE_BLUETOOTH_LE_ADVERTISING_MANAGER_CLIENT_H_ + +#include <map> +#include <string> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/observer_list.h" +#include "bluetooth_le_advertising_manager_client.h" +#include "chromeos/chromeos_export.h" +#include "dbus/object_path.h" +#include "dbus/property.h" + +namespace chromeos { + +class FakeBluetoothLEAdvertisementServiceProvider; + +// FakeBluetoothAdvertisementManagerClient simulates the behavior of the +// Bluetooth +// Daemon's profile manager object and is used both in test cases in place of a +// mock and on the Linux desktop. +class CHROMEOS_EXPORT FakeBluetoothLEAdvertisingManagerClient + : public BluetoothLEAdvertisingManagerClient { + public: + FakeBluetoothLEAdvertisingManagerClient(); + ~FakeBluetoothLEAdvertisingManagerClient() override; + + // DBusClient overrides: + void Init(dbus::Bus* bus) override; + + // BluetoothAdvertisingManagerClient overrides: + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + void RegisterAdvertisement(const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + void UnregisterAdvertisement( + const dbus::ObjectPath& manager_object_path, + const dbus::ObjectPath& advertisement_object_path, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + + // Register, unregister and retrieve pointers to profile server providers. + void RegisterAdvertisementServiceProvider( + FakeBluetoothLEAdvertisementServiceProvider* service_provider); + void UnregisterAdvertisementServiceProvider( + FakeBluetoothLEAdvertisementServiceProvider* service_provider); + FakeBluetoothLEAdvertisementServiceProvider* GetAdvertisementServiceProvider( + const std::string& uuid); + + // Advertising manager path that we simulate. + static const char kAdvertisingManagerPath[]; + + private: + // Map of a D-Bus object path to the FakeBluetoothAdvertisementServiceProvider + // registered for it; maintained by RegisterAdvertisementServiceProvider() and + // UnregisterProfileServiceProvicer() called by the constructor and + // destructor of FakeBluetoothAdvertisementServiceProvider. + typedef std::map<dbus::ObjectPath, + FakeBluetoothLEAdvertisementServiceProvider*> + ServiceProviderMap; + ServiceProviderMap service_provider_map_; + + // Holds the currently registered advertisement. If there is no advertisement + // registered, this path is empty. + dbus::ObjectPath currently_registered_; + + DISALLOW_COPY_AND_ASSIGN(FakeBluetoothLEAdvertisingManagerClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_FAKE_BLUETOOTH_LE_ADVERTISING_MANAGER_CLIENT_H_ |