| Index: chromeos/dbus/fake_bluetooth_device_client.cc
|
| diff --git a/chromeos/dbus/fake_bluetooth_device_client.cc b/chromeos/dbus/fake_bluetooth_device_client.cc
|
| index 3c6e440bed380adf831100881b84d8afa46172d7..4fef274ae862e787101d54d6a51b2c11e29ef466 100644
|
| --- a/chromeos/dbus/fake_bluetooth_device_client.cc
|
| +++ b/chromeos/dbus/fake_bluetooth_device_client.cc
|
| @@ -4,6 +4,11 @@
|
|
|
| #include "chromeos/dbus/fake_bluetooth_device_client.h"
|
|
|
| +#include <fcntl.h>
|
| +#include <unistd.h>
|
| +#include <sys/types.h>
|
| +#include <sys/socket.h>
|
| +
|
| #include <algorithm>
|
| #include <map>
|
| #include <string>
|
| @@ -12,14 +17,19 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| #include "base/message_loop.h"
|
| #include "base/stl_util.h"
|
| +#include "base/threading/worker_pool.h"
|
| #include "base/time.h"
|
| #include "chromeos/dbus/dbus_thread_manager.h"
|
| #include "chromeos/dbus/fake_bluetooth_adapter_client.h"
|
| #include "chromeos/dbus/fake_bluetooth_agent_manager_client.h"
|
| #include "chromeos/dbus/fake_bluetooth_agent_service_provider.h"
|
| #include "chromeos/dbus/fake_bluetooth_input_client.h"
|
| +#include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
|
| +#include "chromeos/dbus/fake_bluetooth_profile_service_provider.h"
|
| +#include "dbus/file_descriptor.h"
|
| #include "dbus/object_path.h"
|
| #include "third_party/cros_system_api/dbus/service_constants.h"
|
|
|
| @@ -28,6 +38,30 @@ namespace {
|
| // Default interval between simulated events.
|
| const int kSimulationIntervalMs = 750;
|
|
|
| +
|
| +void SimulatedProfileSocket(int fd) {
|
| + // Simulate a server-side socket of a profile; read data from the socket,
|
| + // write it back, and then close.
|
| + char buf[1024];
|
| + ssize_t len;
|
| + ssize_t count;
|
| +
|
| + len = read(fd, buf, sizeof buf);
|
| + if (len < 0) {
|
| + close(fd);
|
| + return;
|
| + }
|
| +
|
| + count = len;
|
| + len = write(fd, buf, count);
|
| + if (len < 0) {
|
| + close(fd);
|
| + return;
|
| + }
|
| +
|
| + close(fd);
|
| +}
|
| +
|
| }
|
|
|
| namespace chromeos {
|
| @@ -259,7 +293,63 @@ void FakeBluetoothDeviceClient::ConnectProfile(
|
| const base::Closure& callback,
|
| const ErrorCallback& error_callback) {
|
| VLOG(1) << "ConnectProfile: " << object_path.value() << " " << uuid;
|
| - error_callback.Run(kNoResponseError, "");
|
| +
|
| + FakeBluetoothProfileManagerClient* fake_bluetooth_profile_manager_client =
|
| + static_cast<FakeBluetoothProfileManagerClient*>(
|
| + DBusThreadManager::Get()->
|
| + GetExperimentalBluetoothProfileManagerClient());
|
| + FakeBluetoothProfileServiceProvider* profile_service_provider =
|
| + fake_bluetooth_profile_manager_client->GetProfileServiceProvider(uuid);
|
| + if (profile_service_provider == NULL) {
|
| + error_callback.Run(kNoResponseError, "Missing profile");
|
| + return;
|
| + }
|
| +
|
| + // Make a socket pair of a compatible type with the type used by Bluetooth;
|
| + // spin up a thread to simulate the server side and wrap the client side in
|
| + // a D-Bus file descriptor object.
|
| + int socket_type = SOCK_STREAM;
|
| + if (uuid == FakeBluetoothProfileManagerClient::kL2capUuid)
|
| + socket_type = SOCK_SEQPACKET;
|
| +
|
| + int fds[2];
|
| + if (socketpair(AF_UNIX, socket_type, 0, fds) < 0) {
|
| + error_callback.Run(kNoResponseError, "socketpair call failed");
|
| + return;
|
| + }
|
| +
|
| + int args;
|
| + args = fcntl(fds[1], F_GETFL, NULL);
|
| + if (args < 0) {
|
| + error_callback.Run(kNoResponseError, "failed to get socket flags");
|
| + return;
|
| + }
|
| +
|
| + args |= O_NONBLOCK;
|
| + if (fcntl(fds[1], F_SETFL, args) < 0) {
|
| + error_callback.Run(kNoResponseError, "failed to set socket non-blocking");
|
| + return;
|
| + }
|
| +
|
| + base::WorkerPool::GetTaskRunner(false)->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimulatedProfileSocket,
|
| + fds[0]));
|
| +
|
| + scoped_ptr<dbus::FileDescriptor> fd(new dbus::FileDescriptor(fds[1]));
|
| +
|
| + // Post the new connection to the service provider.
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::Options options;
|
| +
|
| + profile_service_provider->NewConnection(
|
| + object_path,
|
| + fd.Pass(),
|
| + options,
|
| + base::Bind(&FakeBluetoothDeviceClient::ConnectionCallback,
|
| + base::Unretained(this),
|
| + object_path,
|
| + callback,
|
| + error_callback));
|
| }
|
|
|
| void FakeBluetoothDeviceClient::DisconnectProfile(
|
| @@ -268,7 +358,25 @@ void FakeBluetoothDeviceClient::DisconnectProfile(
|
| const base::Closure& callback,
|
| const ErrorCallback& error_callback) {
|
| VLOG(1) << "DisconnectProfile: " << object_path.value() << " " << uuid;
|
| - error_callback.Run(kNoResponseError, "");
|
| +
|
| + FakeBluetoothProfileManagerClient* fake_bluetooth_profile_manager_client =
|
| + static_cast<FakeBluetoothProfileManagerClient*>(
|
| + DBusThreadManager::Get()->
|
| + GetExperimentalBluetoothProfileManagerClient());
|
| + FakeBluetoothProfileServiceProvider* profile_service_provider =
|
| + fake_bluetooth_profile_manager_client->GetProfileServiceProvider(uuid);
|
| + if (profile_service_provider == NULL) {
|
| + error_callback.Run(kNoResponseError, "Missing profile");
|
| + return;
|
| + }
|
| +
|
| + profile_service_provider->RequestDisconnection(
|
| + object_path,
|
| + base::Bind(&FakeBluetoothDeviceClient::DisconnectionCallback,
|
| + base::Unretained(this),
|
| + object_path,
|
| + callback,
|
| + error_callback));
|
| }
|
|
|
| void FakeBluetoothDeviceClient::Pair(
|
| @@ -874,4 +982,45 @@ void FakeBluetoothDeviceClient::SimulateKeypress(
|
| }
|
| }
|
|
|
| +void FakeBluetoothDeviceClient::ConnectionCallback(
|
| + const dbus::ObjectPath& object_path,
|
| + const base::Closure& callback,
|
| + const ErrorCallback& error_callback,
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::Status status) {
|
| + VLOG(1) << "ConnectionCallback: " << object_path.value();
|
| +
|
| + if (status ==
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::SUCCESS) {
|
| + callback.Run();
|
| + } else if (status ==
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::CANCELLED) {
|
| + // TODO(keybuk): tear down this side of the connection
|
| + error_callback.Run(bluetooth_adapter::kErrorFailed, "Canceled");
|
| + } else if (status ==
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::REJECTED) {
|
| + // TODO(keybuk): tear down this side of the connection
|
| + error_callback.Run(bluetooth_adapter::kErrorFailed, "Rejected");
|
| + }
|
| +}
|
| +
|
| +void FakeBluetoothDeviceClient::DisconnectionCallback(
|
| + const dbus::ObjectPath& object_path,
|
| + const base::Closure& callback,
|
| + const ErrorCallback& error_callback,
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::Status status) {
|
| + VLOG(1) << "DisconnectionCallback: " << object_path.value();
|
| +
|
| + if (status ==
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::SUCCESS) {
|
| + // TODO(keybuk): tear down this side of the connection
|
| + callback.Run();
|
| + } else if (status ==
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::CANCELLED) {
|
| + error_callback.Run(bluetooth_adapter::kErrorFailed, "Canceled");
|
| + } else if (status ==
|
| + ExperimentalBluetoothProfileServiceProvider::Delegate::REJECTED) {
|
| + error_callback.Run(bluetooth_adapter::kErrorFailed, "Rejected");
|
| + }
|
| +}
|
| +
|
| } // namespace chromeos
|
|
|