summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chromeos/dbus/fake_bluetooth_device_client.cc533
-rw-r--r--chromeos/dbus/fake_bluetooth_device_client.h17
-rw-r--r--device/bluetooth/bluetooth.gyp2
-rw-r--r--device/bluetooth/bluetooth_adapter.cc34
-rw-r--r--device/bluetooth/bluetooth_adapter.h44
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.cc243
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.h97
-rw-r--r--device/bluetooth/bluetooth_adapter_mac.h5
-rw-r--r--device/bluetooth/bluetooth_adapter_mac.mm4
-rw-r--r--device/bluetooth/bluetooth_adapter_unittest.cc187
-rw-r--r--device/bluetooth/bluetooth_adapter_win.cc4
-rw-r--r--device/bluetooth/bluetooth_adapter_win.h5
-rw-r--r--device/bluetooth/bluetooth_chromeos_unittest.cc368
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.cc51
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.h23
-rw-r--r--device/bluetooth/bluetooth_pairing_chromeos.cc248
-rw-r--r--device/bluetooth/bluetooth_pairing_chromeos.h134
-rw-r--r--device/bluetooth/test/mock_bluetooth_adapter.h10
-rw-r--r--device/device_tests.gyp1
19 files changed, 1409 insertions, 601 deletions
diff --git a/chromeos/dbus/fake_bluetooth_device_client.cc b/chromeos/dbus/fake_bluetooth_device_client.cc
index 08f748a..b77a956 100644
--- a/chromeos/dbus/fake_bluetooth_device_client.cc
+++ b/chromeos/dbus/fake_bluetooth_device_client.cc
@@ -400,105 +400,7 @@ void FakeBluetoothDeviceClient::Pair(
return;
}
- pairing_cancelled_ = false;
-
- FakeBluetoothAgentManagerClient* fake_bluetooth_agent_manager_client =
- static_cast<FakeBluetoothAgentManagerClient*>(
- DBusThreadManager::Get()->GetBluetoothAgentManagerClient());
- FakeBluetoothAgentServiceProvider* agent_service_provider =
- fake_bluetooth_agent_manager_client->GetAgentServiceProvider();
- if (agent_service_provider == NULL) {
- error_callback.Run(kNoResponseError, "Missing agent");
- return;
- }
-
- if (object_path == dbus::ObjectPath(kAppleMousePath) ||
- object_path == dbus::ObjectPath(kMicrosoftMousePath) ||
- object_path == dbus::ObjectPath(kUnconnectableDevicePath)) {
- // No need to call anything on the pairing delegate, just wait 3 times
- // the interval before acting as if the other end accepted it.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
- base::Unretained(this),
- object_path, callback, error_callback),
- base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
-
- } else if (object_path == dbus::ObjectPath(kAppleKeyboardPath)) {
- // Display a Pincode, and wait 7 times the interval before acting as
- // if the other end accepted it.
- agent_service_provider->DisplayPinCode(object_path, "123456");
-
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
- base::Unretained(this),
- object_path, callback, error_callback),
- base::TimeDelta::FromMilliseconds(7 * simulation_interval_ms_));
-
- } else if (object_path == dbus::ObjectPath(kVanishingDevicePath)) {
- // The vanishing device simulates being too far away, and thus times out.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeBluetoothDeviceClient::TimeoutSimulatedPairing,
- base::Unretained(this),
- object_path, error_callback),
- base::TimeDelta::FromMilliseconds(4 * simulation_interval_ms_));
-
- } else if (object_path == dbus::ObjectPath(kMotorolaKeyboardPath)) {
- // Display a passkey, and each interval act as if another key was entered
- // for it.
- agent_service_provider->DisplayPasskey(object_path, 123456, 0);
-
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
- base::Unretained(this),
- 1, object_path, callback, error_callback),
- base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
-
- } else if (object_path == dbus::ObjectPath(kSonyHeadphonesPath)) {
- // Request a Pincode.
- agent_service_provider->RequestPinCode(
- object_path,
- base::Bind(&FakeBluetoothDeviceClient::PinCodeCallback,
- base::Unretained(this),
- object_path,
- callback,
- error_callback));
-
- } else if (object_path == dbus::ObjectPath(kPhonePath)) {
- // Request confirmation of a Passkey.
- agent_service_provider->RequestConfirmation(
- object_path, 123456,
- base::Bind(&FakeBluetoothDeviceClient::ConfirmationCallback,
- base::Unretained(this),
- object_path,
- callback,
- error_callback));
-
- } else if (object_path == dbus::ObjectPath(kWeirdDevicePath)) {
- // Request a Passkey from the user.
- agent_service_provider->RequestPasskey(
- object_path,
- base::Bind(&FakeBluetoothDeviceClient::PasskeyCallback,
- base::Unretained(this),
- object_path,
- callback,
- error_callback));
-
- } else if (object_path == dbus::ObjectPath(kUnpairableDevicePath)) {
- // Fails the pairing with an org.bluez.Error.Failed error.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeBluetoothDeviceClient::FailSimulatedPairing,
- base::Unretained(this),
- object_path, error_callback),
- base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
-
- } else {
- error_callback.Run(kNoResponseError, "No pairing fake");
- }
+ SimulatePairing(object_path, false, callback, error_callback);
}
void FakeBluetoothDeviceClient::CancelPairing(
@@ -534,6 +436,106 @@ void FakeBluetoothDeviceClient::SetSimulationIntervalMs(int interval_ms) {
simulation_interval_ms_ = interval_ms;
}
+void FakeBluetoothDeviceClient::CreateDevice(
+ const dbus::ObjectPath& adapter_path,
+ const dbus::ObjectPath& device_path) {
+ if (std::find(device_list_.begin(),
+ device_list_.end(), device_path) != device_list_.end())
+ return;
+
+ Properties* properties = new Properties(base::Bind(
+ &FakeBluetoothDeviceClient::OnPropertyChanged,
+ base::Unretained(this),
+ device_path));
+ properties->adapter.ReplaceValue(adapter_path);
+
+ if (device_path == dbus::ObjectPath(kAppleMousePath)) {
+ properties->address.ReplaceValue(kAppleMouseAddress);
+ properties->bluetooth_class.ReplaceValue(kAppleMouseClass);
+ properties->name.ReplaceValue("Fake Apple Magic Mouse");
+ properties->alias.ReplaceValue(kAppleMouseName);
+
+ std::vector<std::string> uuids;
+ uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
+ properties->uuids.ReplaceValue(uuids);
+
+ } else if (device_path == dbus::ObjectPath(kAppleKeyboardPath)) {
+ properties->address.ReplaceValue(kAppleKeyboardAddress);
+ properties->bluetooth_class.ReplaceValue(kAppleKeyboardClass);
+ properties->name.ReplaceValue("Fake Apple Wireless Keyboard");
+ properties->alias.ReplaceValue(kAppleKeyboardName);
+
+ std::vector<std::string> uuids;
+ uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
+ properties->uuids.ReplaceValue(uuids);
+
+ } else if (device_path == dbus::ObjectPath(kVanishingDevicePath)) {
+ properties->address.ReplaceValue(kVanishingDeviceAddress);
+ properties->bluetooth_class.ReplaceValue(kVanishingDeviceClass);
+ properties->name.ReplaceValue("Fake Vanishing Device");
+ properties->alias.ReplaceValue(kVanishingDeviceName);
+
+ } else if (device_path == dbus::ObjectPath(kMicrosoftMousePath)) {
+ properties->address.ReplaceValue(kMicrosoftMouseAddress);
+ properties->bluetooth_class.ReplaceValue(kMicrosoftMouseClass);
+ properties->name.ReplaceValue("Fake Microsoft Mouse");
+ properties->alias.ReplaceValue(kMicrosoftMouseName);
+
+ std::vector<std::string> uuids;
+ uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
+ properties->uuids.ReplaceValue(uuids);
+
+ } else if (device_path == dbus::ObjectPath(kMotorolaKeyboardPath)) {
+ properties->address.ReplaceValue(kMotorolaKeyboardAddress);
+ properties->bluetooth_class.ReplaceValue(kMotorolaKeyboardClass);
+ properties->name.ReplaceValue("Fake Motorola Keyboard");
+ properties->alias.ReplaceValue(kMotorolaKeyboardName);
+
+ std::vector<std::string> uuids;
+ uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
+ properties->uuids.ReplaceValue(uuids);
+
+ } else if (device_path == dbus::ObjectPath(kSonyHeadphonesPath)) {
+ properties->address.ReplaceValue(kSonyHeadphonesAddress);
+ properties->bluetooth_class.ReplaceValue(kSonyHeadphonesClass);
+ properties->name.ReplaceValue("Fake Sony Headphones");
+ properties->alias.ReplaceValue(kSonyHeadphonesName);
+
+ } else if (device_path == dbus::ObjectPath(kPhonePath)) {
+ properties->address.ReplaceValue(kPhoneAddress);
+ properties->bluetooth_class.ReplaceValue(kPhoneClass);
+ properties->name.ReplaceValue("Fake Phone");
+ properties->alias.ReplaceValue(kPhoneName);
+
+ } else if (device_path == dbus::ObjectPath(kWeirdDevicePath)) {
+ properties->address.ReplaceValue(kWeirdDeviceAddress);
+ properties->bluetooth_class.ReplaceValue(kWeirdDeviceClass);
+ properties->name.ReplaceValue("Fake Weird Device");
+ properties->alias.ReplaceValue(kWeirdDeviceName);
+
+ } else if (device_path == dbus::ObjectPath(kUnconnectableDevicePath)) {
+ properties->address.ReplaceValue(kUnconnectableDeviceAddress);
+ properties->bluetooth_class.ReplaceValue(kUnconnectableDeviceClass);
+ properties->name.ReplaceValue("Fake Unconnectable Device");
+ properties->alias.ReplaceValue(kUnconnectableDeviceName);
+
+ } else if (device_path == dbus::ObjectPath(kUnpairableDevicePath)) {
+ properties->address.ReplaceValue(kUnpairableDeviceAddress);
+ properties->bluetooth_class.ReplaceValue(kUnpairableDeviceClass);
+ properties->name.ReplaceValue("Fake Unpairable Device");
+ properties->alias.ReplaceValue(kUnpairableDeviceName);
+
+ } else {
+ NOTREACHED();
+
+ }
+
+ properties_map_[device_path] = properties;
+ device_list_.push_back(device_path);
+ FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
+ DeviceAdded(device_path));
+}
+
void FakeBluetoothDeviceClient::RemoveDevice(
const dbus::ObjectPath& adapter_path,
const dbus::ObjectPath& device_path) {
@@ -578,222 +580,34 @@ void FakeBluetoothDeviceClient::DiscoverySimulationTimer() {
// for a discovery process.
VLOG(1) << "discovery simulation, step " << discovery_simulation_step_;
if (discovery_simulation_step_ == 2) {
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kAppleMousePath)) == device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kAppleMousePath)));
- properties->address.ReplaceValue(kAppleMouseAddress);
- properties->bluetooth_class.ReplaceValue(kAppleMouseClass);
- properties->name.ReplaceValue("Fake Apple Magic Mouse");
- properties->alias.ReplaceValue(kAppleMouseName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- std::vector<std::string> uuids;
- uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
- properties->uuids.ReplaceValue(uuids);
-
- properties_map_[dbus::ObjectPath(kAppleMousePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kAppleMousePath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kAppleMousePath)));
- }
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kAppleMousePath));
} else if (discovery_simulation_step_ == 4) {
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kAppleKeyboardPath)) == device_list_.end()) {
- Properties *properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kAppleKeyboardPath)));
- properties->address.ReplaceValue(kAppleKeyboardAddress);
- properties->bluetooth_class.ReplaceValue(kAppleKeyboardClass);
- properties->name.ReplaceValue("Fake Apple Wireless Keyboard");
- properties->alias.ReplaceValue(kAppleKeyboardName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- std::vector<std::string> uuids;
- uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
- properties->uuids.ReplaceValue(uuids);
-
- properties_map_[dbus::ObjectPath(kAppleKeyboardPath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kAppleKeyboardPath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kAppleKeyboardPath)));
- }
-
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kVanishingDevicePath)) ==
- device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kVanishingDevicePath)));
- properties->address.ReplaceValue(kVanishingDeviceAddress);
- properties->bluetooth_class.ReplaceValue(kVanishingDeviceClass);
- properties->name.ReplaceValue("Fake Vanishing Device");
- properties->alias.ReplaceValue(kVanishingDeviceName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- properties_map_[dbus::ObjectPath(kVanishingDevicePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kVanishingDevicePath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kVanishingDevicePath)));
- }
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kAppleKeyboardPath));
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kVanishingDevicePath));
} else if (discovery_simulation_step_ == 7) {
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kMicrosoftMousePath)) ==
- device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kMicrosoftMousePath)));
- properties->address.ReplaceValue(kMicrosoftMouseAddress);
- properties->bluetooth_class.ReplaceValue(kMicrosoftMouseClass);
- properties->name.ReplaceValue("Fake Microsoft Mouse");
- properties->alias.ReplaceValue(kMicrosoftMouseName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- std::vector<std::string> uuids;
- uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
- properties->uuids.ReplaceValue(uuids);
-
- properties_map_[dbus::ObjectPath(kMicrosoftMousePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kMicrosoftMousePath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kMicrosoftMousePath)));
- }
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kMicrosoftMousePath));
} else if (discovery_simulation_step_ == 8) {
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kMotorolaKeyboardPath)) ==
- device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kMotorolaKeyboardPath)));
- properties->address.ReplaceValue(kMotorolaKeyboardAddress);
- properties->bluetooth_class.ReplaceValue(kMotorolaKeyboardClass);
- properties->name.ReplaceValue("Fake Motorola Keyboard");
- properties->alias.ReplaceValue(kMotorolaKeyboardName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- std::vector<std::string> uuids;
- uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
- properties->uuids.ReplaceValue(uuids);
-
- properties_map_[dbus::ObjectPath(kMotorolaKeyboardPath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kMotorolaKeyboardPath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kMotorolaKeyboardPath)));
- }
-
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kSonyHeadphonesPath)) ==
- device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kSonyHeadphonesPath)));
- properties->address.ReplaceValue(kSonyHeadphonesAddress);
- properties->bluetooth_class.ReplaceValue(kSonyHeadphonesClass);
- properties->name.ReplaceValue("Fake Sony Headphones");
- properties->alias.ReplaceValue(kSonyHeadphonesName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- properties_map_[dbus::ObjectPath(kSonyHeadphonesPath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kSonyHeadphonesPath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kSonyHeadphonesPath)));
- }
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kMotorolaKeyboardPath));
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kSonyHeadphonesPath));
} else if (discovery_simulation_step_ == 10) {
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kPhonePath)) == device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kPhonePath)));
- properties->address.ReplaceValue(kPhoneAddress);
- properties->bluetooth_class.ReplaceValue(kPhoneClass);
- properties->name.ReplaceValue("Fake Phone");
- properties->alias.ReplaceValue(kPhoneName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- properties_map_[dbus::ObjectPath(kPhonePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kPhonePath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kPhonePath)));
- }
-
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kWeirdDevicePath)) == device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kWeirdDevicePath)));
- properties->address.ReplaceValue(kWeirdDeviceAddress);
- properties->bluetooth_class.ReplaceValue(kWeirdDeviceClass);
- properties->name.ReplaceValue("Fake Weird Device");
- properties->alias.ReplaceValue(kWeirdDeviceName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- properties_map_[dbus::ObjectPath(kWeirdDevicePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kWeirdDevicePath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kWeirdDevicePath)));
- }
-
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kUnconnectableDevicePath)) ==
- device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kUnconnectableDevicePath)));
- properties->address.ReplaceValue(kUnconnectableDeviceAddress);
- properties->bluetooth_class.ReplaceValue(kUnconnectableDeviceClass);
- properties->name.ReplaceValue("Fake Unconnectable Device");
- properties->alias.ReplaceValue(kUnconnectableDeviceName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- properties_map_[dbus::ObjectPath(kUnconnectableDevicePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kUnconnectableDevicePath));
- FOR_EACH_OBSERVER(
- BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kUnconnectableDevicePath)));
- }
-
- if (std::find(device_list_.begin(), device_list_.end(),
- dbus::ObjectPath(kUnpairableDevicePath)) ==
- device_list_.end()) {
- Properties* properties = new Properties(base::Bind(
- &FakeBluetoothDeviceClient::OnPropertyChanged,
- base::Unretained(this),
- dbus::ObjectPath(kUnpairableDevicePath)));
- properties->address.ReplaceValue(kUnpairableDeviceAddress);
- properties->bluetooth_class.ReplaceValue(kUnpairableDeviceClass);
- properties->name.ReplaceValue("Fake Unpairable Device");
- properties->alias.ReplaceValue(kUnpairableDeviceName);
- properties->adapter.ReplaceValue(
- dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
-
- properties_map_[dbus::ObjectPath(kUnpairableDevicePath)] = properties;
- device_list_.push_back(dbus::ObjectPath(kUnpairableDevicePath));
- FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
- DeviceAdded(dbus::ObjectPath(kUnpairableDevicePath)));
- }
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kPhonePath));
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kWeirdDevicePath));
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kUnconnectableDevicePath));
+ CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(kUnpairableDevicePath));
} else if (discovery_simulation_step_ == 13) {
RemoveDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
@@ -813,6 +627,109 @@ void FakeBluetoothDeviceClient::DiscoverySimulationTimer() {
}
+void FakeBluetoothDeviceClient::SimulatePairing(
+ const dbus::ObjectPath& object_path,
+ bool incoming_request,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ pairing_cancelled_ = false;
+
+ FakeBluetoothAgentManagerClient* fake_bluetooth_agent_manager_client =
+ static_cast<FakeBluetoothAgentManagerClient*>(
+ DBusThreadManager::Get()->GetBluetoothAgentManagerClient());
+ FakeBluetoothAgentServiceProvider* agent_service_provider =
+ fake_bluetooth_agent_manager_client->GetAgentServiceProvider();
+ CHECK(agent_service_provider != NULL);
+
+ if (object_path == dbus::ObjectPath(kAppleMousePath) ||
+ object_path == dbus::ObjectPath(kMicrosoftMousePath) ||
+ object_path == dbus::ObjectPath(kUnconnectableDevicePath)) {
+ // No need to call anything on the pairing delegate, just wait 3 times
+ // the interval before acting as if the other end accepted it.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
+ base::Unretained(this),
+ object_path, callback, error_callback),
+ base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
+
+ } else if (object_path == dbus::ObjectPath(kAppleKeyboardPath)) {
+ // Display a Pincode, and wait 7 times the interval before acting as
+ // if the other end accepted it.
+ agent_service_provider->DisplayPinCode(object_path, "123456");
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
+ base::Unretained(this),
+ object_path, callback, error_callback),
+ base::TimeDelta::FromMilliseconds(7 * simulation_interval_ms_));
+
+ } else if (object_path == dbus::ObjectPath(kVanishingDevicePath)) {
+ // The vanishing device simulates being too far away, and thus times out.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&FakeBluetoothDeviceClient::TimeoutSimulatedPairing,
+ base::Unretained(this),
+ object_path, error_callback),
+ base::TimeDelta::FromMilliseconds(4 * simulation_interval_ms_));
+
+ } else if (object_path == dbus::ObjectPath(kMotorolaKeyboardPath)) {
+ // Display a passkey, and each interval act as if another key was entered
+ // for it.
+ agent_service_provider->DisplayPasskey(object_path, 123456, 0);
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
+ base::Unretained(this),
+ 1, object_path, callback, error_callback),
+ base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
+
+ } else if (object_path == dbus::ObjectPath(kSonyHeadphonesPath)) {
+ // Request a Pincode.
+ agent_service_provider->RequestPinCode(
+ object_path,
+ base::Bind(&FakeBluetoothDeviceClient::PinCodeCallback,
+ base::Unretained(this),
+ object_path,
+ callback,
+ error_callback));
+
+ } else if (object_path == dbus::ObjectPath(kPhonePath)) {
+ // Request confirmation of a Passkey.
+ agent_service_provider->RequestConfirmation(
+ object_path, 123456,
+ base::Bind(&FakeBluetoothDeviceClient::ConfirmationCallback,
+ base::Unretained(this),
+ object_path,
+ callback,
+ error_callback));
+
+ } else if (object_path == dbus::ObjectPath(kWeirdDevicePath)) {
+ // Request a Passkey from the user.
+ agent_service_provider->RequestPasskey(
+ object_path,
+ base::Bind(&FakeBluetoothDeviceClient::PasskeyCallback,
+ base::Unretained(this),
+ object_path,
+ callback,
+ error_callback));
+
+ } else if (object_path == dbus::ObjectPath(kUnpairableDevicePath)) {
+ // Fails the pairing with an org.bluez.Error.Failed error.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&FakeBluetoothDeviceClient::FailSimulatedPairing,
+ base::Unretained(this),
+ object_path, error_callback),
+ base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
+
+ } else {
+ error_callback.Run(kNoResponseError, "No pairing fake");
+ }
+}
+
void FakeBluetoothDeviceClient::CompleteSimulatedPairing(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
@@ -822,7 +739,7 @@ void FakeBluetoothDeviceClient::CompleteSimulatedPairing(
pairing_cancelled_ = false;
error_callback.Run(bluetooth_device::kErrorAuthenticationCanceled,
- "Cancaled");
+ "Cancelled");
} else {
Properties* properties = GetProperties(object_path);
diff --git a/chromeos/dbus/fake_bluetooth_device_client.h b/chromeos/dbus/fake_bluetooth_device_client.h
index 95b21ba..e232416 100644
--- a/chromeos/dbus/fake_bluetooth_device_client.h
+++ b/chromeos/dbus/fake_bluetooth_device_client.h
@@ -72,14 +72,27 @@ class CHROMEOS_EXPORT FakeBluetoothDeviceClient
void SetSimulationIntervalMs(int interval_ms);
- // Simulate discovery of devices for the given adapter.
+ // Simulates discovery of devices for the given adapter.
void BeginDiscoverySimulation(const dbus::ObjectPath& adapter_path);
void EndDiscoverySimulation(const dbus::ObjectPath& adapter_path);
- // Remove a device from the set we return for the given adapter.
+ // Creates a device from the set we return for the given adapter.
+ void CreateDevice(const dbus::ObjectPath& adapter_path,
+ const dbus::ObjectPath& device_path);
+
+ // Removes a device from the set we return for the given adapter.
void RemoveDevice(const dbus::ObjectPath& adapter_path,
const dbus::ObjectPath& device_path);
+ // Simulates a pairing for the device with the given D-Bus object path,
+ // |object_path|. Set |incoming_request| to true if simulating an incoming
+ // pairing request, false for an outgoing one. On successful completion
+ // |callback| will be called, on failure, |error_callback| is called.
+ void SimulatePairing(const dbus::ObjectPath& object_path,
+ bool incoming_request,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback);
+
// Object paths, names, addresses and bluetooth classes of the devices
// we can emulate.
static const char kPairedDevicePath[];
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index c4012bd..1f13ef3 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -48,6 +48,8 @@
'bluetooth_init_win.cc',
'bluetooth_init_win.h',
'bluetooth_out_of_band_pairing_data.h',
+ 'bluetooth_pairing_chromeos.cc',
+ 'bluetooth_pairing_chromeos.h',
'bluetooth_profile.cc',
'bluetooth_profile.h',
'bluetooth_profile_chromeos.cc',
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
index bb372f1..1462f49 100644
--- a/device/bluetooth/bluetooth_adapter.cc
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -62,4 +62,38 @@ const BluetoothDevice* BluetoothAdapter::GetDevice(
return NULL;
}
+void BluetoothAdapter::AddPairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate,
+ PairingDelegatePriority priority) {
+ // Remove the delegate, if it already exists, before inserting to allow a
+ // change of priority.
+ RemovePairingDelegate(pairing_delegate);
+
+ // Find the first point with a lower priority, or the end of the list.
+ std::list<PairingDelegatePair>::iterator iter = pairing_delegates_.begin();
+ while (iter != pairing_delegates_.end() && iter->second >= priority)
+ ++iter;
+
+ pairing_delegates_.insert(iter, std::make_pair(pairing_delegate, priority));
+}
+
+void BluetoothAdapter::RemovePairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ for (std::list<PairingDelegatePair>::iterator iter =
+ pairing_delegates_.begin(); iter != pairing_delegates_.end(); ++iter) {
+ if (iter->first == pairing_delegate) {
+ RemovePairingDelegateInternal(pairing_delegate);
+ pairing_delegates_.erase(iter);
+ return;
+ }
+ }
+}
+
+BluetoothDevice::PairingDelegate* BluetoothAdapter::DefaultPairingDelegate() {
+ if (pairing_delegates_.empty())
+ return NULL;
+
+ return pairing_delegates_.front().first;
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h
index 42fe8db..cec53e0 100644
--- a/device/bluetooth/bluetooth_adapter.h
+++ b/device/bluetooth/bluetooth_adapter.h
@@ -5,17 +5,17 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_H_
+#include <list>
#include <map>
#include <string>
-#include <vector>
+#include <utility>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "device/bluetooth/bluetooth_device.h"
namespace device {
-class BluetoothDevice;
-
struct BluetoothOutOfBandPairingData;
// BluetoothAdapter represents a local Bluetooth adapter which may be used to
@@ -175,6 +175,33 @@ class BluetoothAdapter : public base::RefCounted<BluetoothAdapter> {
const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) = 0;
+ // Possible priorities for AddPairingDelegate(), low is intended for
+ // permanent UI and high is intended for interactive UI or applications.
+ enum PairingDelegatePriority {
+ PAIRING_DELEGATE_PRIORITY_LOW,
+ PAIRING_DELEGATE_PRIORITY_HIGH
+ };
+
+ // Adds a default pairing delegate with priority |priority|, method calls
+ // will be made on |pairing_delegate| for incoming pairing requests if the
+ // priority is higher than any other registered, or for those of the same
+ // priority, the first registered.
+ //
+ // |pairing_delegate| must not be freed without first calling
+ // RemovePairingDelegate().
+ virtual void AddPairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate,
+ PairingDelegatePriority priority);
+
+ // Removes a previously added pairing delegate.
+ virtual void RemovePairingDelegate(
+ BluetoothDevice::PairingDelegate* pairing_delegate);
+
+ // Returns the first registered pairing delegate with the highest priority,
+ // or NULL if no delegate is registered. Used to select the delegate for
+ // incoming pairing requests.
+ virtual BluetoothDevice::PairingDelegate* DefaultPairingDelegate();
+
protected:
friend class base::RefCounted<BluetoothAdapter>;
BluetoothAdapter();
@@ -215,12 +242,23 @@ class BluetoothAdapter : public base::RefCounted<BluetoothAdapter> {
virtual void RemoveDiscoverySession(const base::Closure& callback,
const ErrorCallback& error_callback) = 0;
+ // Called by RemovePairingDelegate() in order to perform any class-specific
+ // internal functionality necessary to remove the pairing delegate, such as
+ // cleaning up ongoing pairings using it.
+ virtual void RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) = 0;
+
// Devices paired with, connected to, discovered by, or visible to the
// adapter. The key is the Bluetooth address of the device and the value
// is the BluetoothDevice object whose lifetime is managed by the
// adapter instance.
typedef std::map<const std::string, BluetoothDevice*> DevicesMap;
DevicesMap devices_;
+
+ // Default pairing delegates registered with the adapter.
+ typedef std::pair<BluetoothDevice::PairingDelegate*,
+ PairingDelegatePriority> PairingDelegatePair;
+ std::list<PairingDelegatePair> pairing_delegates_;
};
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
index 29bc05e..9539ebb 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -18,6 +18,7 @@
#include "chromeos/dbus/dbus_thread_manager.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_chromeos.h"
+#include "device/bluetooth/bluetooth_pairing_chromeos.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using device::BluetoothAdapter;
@@ -29,19 +30,6 @@ namespace {
// exist per D-Bus connection, it just has to be unique within Chromium.
const char kAgentPath[] = "/org/chromium/bluetooth_agent";
-// Histogram enumerations for pairing methods.
-enum UMAPairingMethod {
- UMA_PAIRING_METHOD_NONE,
- UMA_PAIRING_METHOD_REQUEST_PINCODE,
- UMA_PAIRING_METHOD_REQUEST_PASSKEY,
- UMA_PAIRING_METHOD_DISPLAY_PINCODE,
- UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
- UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
- // NOTE: Add new pairing methods immediately above this line. Make sure to
- // update the enum list in tools/histogram/histograms.xml accordingly.
- UMA_PAIRING_METHOD_COUNT
-};
-
void OnUnregisterAgentError(const std::string& error_name,
const std::string& error_message) {
LOG(WARNING) << "Failed to unregister pairing agent: "
@@ -219,6 +207,22 @@ void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
error_callback.Run();
}
+void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ // Before removing a pairing delegate make sure that there aren't any devices
+ // currently using it; if there are, clear the pairing context which will
+ // make any responses no-ops.
+ for (DevicesMap::iterator iter = devices_.begin();
+ iter != devices_.end(); ++iter) {
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(iter->second);
+
+ BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
+ if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
+ device_chromeos->EndPairing();
+ }
+}
+
void BluetoothAdapterChromeOS::AdapterAdded(
const dbus::ObjectPath& object_path) {
// Set the adapter to the newly added adapter only if no adapter is present.
@@ -352,22 +356,13 @@ void BluetoothAdapterChromeOS::RequestPinCode(
DCHECK(agent_.get());
VLOG(1) << device_path.value() << ": RequestPinCode";
- BluetoothDeviceChromeOS* device_chromeos;
- PairingContext* pairing_context;
- if (!GetDeviceAndPairingContext(device_path,
- &device_chromeos, &pairing_context)) {
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
callback.Run(REJECTED, "");
return;
}
- UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
- UMA_PAIRING_METHOD_REQUEST_PINCODE,
- UMA_PAIRING_METHOD_COUNT);
-
- DCHECK(pairing_context->pincode_callback_.is_null());
- pairing_context->pincode_callback_ = callback;
- pairing_context->pairing_delegate_->RequestPinCode(device_chromeos);
- pairing_context->pairing_delegate_used_ = true;
+ pairing->RequestPinCode(callback);
}
void BluetoothAdapterChromeOS::DisplayPinCode(
@@ -376,18 +371,11 @@ void BluetoothAdapterChromeOS::DisplayPinCode(
DCHECK(agent_.get());
VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
- BluetoothDeviceChromeOS* device_chromeos;
- PairingContext* pairing_context;
- if (!GetDeviceAndPairingContext(device_path,
- &device_chromeos, &pairing_context))
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing)
return;
- UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
- UMA_PAIRING_METHOD_DISPLAY_PINCODE,
- UMA_PAIRING_METHOD_COUNT);
-
- pairing_context->pairing_delegate_->DisplayPinCode(device_chromeos, pincode);
- pairing_context->pairing_delegate_used_ = true;
+ pairing->DisplayPinCode(pincode);
}
void BluetoothAdapterChromeOS::RequestPasskey(
@@ -396,22 +384,13 @@ void BluetoothAdapterChromeOS::RequestPasskey(
DCHECK(agent_.get());
VLOG(1) << device_path.value() << ": RequestPasskey";
- BluetoothDeviceChromeOS* device_chromeos;
- PairingContext* pairing_context;
- if (!GetDeviceAndPairingContext(device_path,
- &device_chromeos, &pairing_context)) {
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
callback.Run(REJECTED, 0);
return;
}
- UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
- UMA_PAIRING_METHOD_REQUEST_PASSKEY,
- UMA_PAIRING_METHOD_COUNT);
-
- DCHECK(pairing_context->passkey_callback_.is_null());
- pairing_context->passkey_callback_ = callback;
- pairing_context->pairing_delegate_->RequestPasskey(device_chromeos);
- pairing_context->pairing_delegate_used_ = true;
+ pairing->RequestPasskey(callback);
}
void BluetoothAdapterChromeOS::DisplayPasskey(
@@ -422,23 +401,14 @@ void BluetoothAdapterChromeOS::DisplayPasskey(
VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
<< " (" << entered << " entered)";
- BluetoothDeviceChromeOS* device_chromeos;
- PairingContext* pairing_context;
- if (!GetDeviceAndPairingContext(device_path,
- &device_chromeos, &pairing_context))
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing)
return;
if (entered == 0)
- UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
- UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
- UMA_PAIRING_METHOD_COUNT);
-
- if (entered == 0)
- pairing_context->pairing_delegate_->DisplayPasskey(device_chromeos,
- passkey);
+ pairing->DisplayPasskey(passkey);
- pairing_context->pairing_delegate_->KeysEntered(device_chromeos, entered);
- pairing_context->pairing_delegate_used_ = true;
+ pairing->KeysEntered(entered);
}
void BluetoothAdapterChromeOS::RequestConfirmation(
@@ -448,22 +418,13 @@ void BluetoothAdapterChromeOS::RequestConfirmation(
DCHECK(agent_.get());
VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
- BluetoothDeviceChromeOS* device_chromeos;
- PairingContext* pairing_context;
- if (!GetDeviceAndPairingContext(device_path,
- &device_chromeos, &pairing_context)) {
+ BluetoothPairingChromeOS* pairing = GetPairing(device_path);
+ if (!pairing) {
callback.Run(REJECTED);
return;
}
- UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
- UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
- UMA_PAIRING_METHOD_COUNT);
-
- DCHECK(pairing_context->confirmation_callback_.is_null());
- pairing_context->confirmation_callback_ = callback;
- pairing_context->pairing_delegate_->ConfirmPasskey(device_chromeos, passkey);
- pairing_context->pairing_delegate_used_ = true;
+ pairing->RequestConfirmation(passkey, callback);
}
void BluetoothAdapterChromeOS::RequestAuthorization(
@@ -492,110 +453,37 @@ void BluetoothAdapterChromeOS::Cancel() {
VLOG(1) << "Cancel";
}
-bool BluetoothAdapterChromeOS::PairingContext::ExpectingPinCode() const {
- return !pincode_callback_.is_null();
-}
-
-bool BluetoothAdapterChromeOS::PairingContext::ExpectingPasskey() const {
- return !passkey_callback_.is_null();
-}
-
-bool BluetoothAdapterChromeOS::PairingContext::ExpectingConfirmation() const {
- return !confirmation_callback_.is_null();
-}
-
-void BluetoothAdapterChromeOS::PairingContext::SetPinCode(
- const std::string& pincode) {
- if (pincode_callback_.is_null())
- return;
-
- pincode_callback_.Run(SUCCESS, pincode);
- pincode_callback_.Reset();
-}
-
-void BluetoothAdapterChromeOS::PairingContext::SetPasskey(uint32 passkey) {
- if (passkey_callback_.is_null())
- return;
-
- passkey_callback_.Run(SUCCESS, passkey);
- passkey_callback_.Reset();
-}
-
-void BluetoothAdapterChromeOS::PairingContext::ConfirmPairing() {
- if (confirmation_callback_.is_null())
- return;
-
- confirmation_callback_.Run(SUCCESS);
- confirmation_callback_.Reset();
-}
-
-bool BluetoothAdapterChromeOS::PairingContext::RejectPairing() {
- return RunPairingCallbacks(REJECTED);
-}
-
-bool BluetoothAdapterChromeOS::PairingContext::CancelPairing() {
- return RunPairingCallbacks(CANCELLED);
-}
-
-BluetoothAdapterChromeOS::PairingContext::PairingContext(
- BluetoothDevice::PairingDelegate* pairing_delegate)
- : pairing_delegate_(pairing_delegate),
- pairing_delegate_used_(false) {
- VLOG(1) << "Created PairingContext";
-}
-
-BluetoothAdapterChromeOS::PairingContext::~PairingContext() {
- VLOG(1) << "Destroying PairingContext";
-
- if (!pairing_delegate_used_)
- UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
- UMA_PAIRING_METHOD_NONE,
- UMA_PAIRING_METHOD_COUNT);
+void BluetoothAdapterChromeOS::OnRegisterAgent() {
+ VLOG(1) << "Pairing agent registered, requesting to be made default";
- DCHECK(pincode_callback_.is_null());
- DCHECK(passkey_callback_.is_null());
- DCHECK(confirmation_callback_.is_null());
+ DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
+ RequestDefaultAgent(
+ dbus::ObjectPath(kAgentPath),
+ base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
+ weak_ptr_factory_.GetWeakPtr()));
- pairing_delegate_ = NULL;
}
-bool BluetoothAdapterChromeOS::PairingContext::RunPairingCallbacks(
- BluetoothAgentServiceProvider::Delegate::Status status) {
- pairing_delegate_used_ = true;
-
- bool callback_run = false;
- if (!pincode_callback_.is_null()) {
- pincode_callback_.Run(status, "");
- pincode_callback_.Reset();
- callback_run = true;
- }
-
- if (!passkey_callback_.is_null()) {
- passkey_callback_.Run(status, 0);
- passkey_callback_.Reset();
- callback_run = true;
- }
-
- if (!confirmation_callback_.is_null()) {
- confirmation_callback_.Run(status);
- confirmation_callback_.Reset();
- callback_run = true;
- }
+void BluetoothAdapterChromeOS::OnRegisterAgentError(
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << ": Failed to register pairing agent: "
+ << error_name << ": " << error_message;
- return callback_run;
+ agent_.reset();
}
-void BluetoothAdapterChromeOS::OnRegisterAgent() {
- VLOG(1) << "Pairing agent registered";
+void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
+ VLOG(1) << "Pairing agent now default";
}
-void BluetoothAdapterChromeOS::OnRegisterAgentError(
+void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
const std::string& error_name,
const std::string& error_message) {
- LOG(WARNING) << ": Failed to register pairing agent: "
+ LOG(WARNING) << ": Failed to make pairing agent default: "
<< error_name << ": " << error_message;
-
- agent_.reset();
}
BluetoothDeviceChromeOS*
@@ -612,26 +500,27 @@ BluetoothAdapterChromeOS::GetDeviceWithPath(
return NULL;
}
-bool BluetoothAdapterChromeOS::GetDeviceAndPairingContext(
- const dbus::ObjectPath& object_path,
- BluetoothDeviceChromeOS** device_chromeos,
- PairingContext** pairing_context)
+BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
+ const dbus::ObjectPath& object_path)
{
- *device_chromeos = GetDeviceWithPath(object_path);
+ BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
if (!device_chromeos) {
LOG(WARNING) << "Pairing Agent request for unknown device: "
<< object_path.value();
- return false;
+ return NULL;
}
- *pairing_context = (*device_chromeos)->pairing_context_.get();
- if (*pairing_context)
- return true;
+ BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
+ if (pairing)
+ return pairing;
+
+ // The device doesn't have its own pairing context, so this is an incoming
+ // pairing request that should use our best default delegate (if we have one).
+ BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
+ if (!pairing_delegate)
+ return NULL;
- // TODO(keybuk): this is the point we need a default pairing delegate, create
- // a PairingContext with that passed in, set it as the context on the device
- // and return true.
- return false;
+ return device_chromeos->BeginPairing(pairing_delegate);
}
void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h
index f48a8a8..c8b5ea6 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.h
+++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -27,6 +27,7 @@ namespace chromeos {
class BluetoothChromeOSTest;
class BluetoothDeviceChromeOS;
+class BluetoothPairingChromeOS;
// The BluetoothAdapterChromeOS class implements BluetoothAdapter for the
// Chrome OS platform.
@@ -65,6 +66,11 @@ class BluetoothAdapterChromeOS
callback,
const ErrorCallback& error_callback) OVERRIDE;
+ protected:
+ // BluetoothAdapter override
+ virtual void RemovePairingDelegateInternal(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE;
+
private:
friend class device::BluetoothAdapterFactory;
friend class BluetoothChromeOSTest;
@@ -123,96 +129,29 @@ class BluetoothAdapterChromeOS
// PairingContext is an API between BluetoothAdapterChromeOS and
// BluetoothDeviceChromeOS for a single pairing attempt, wrapping the
// callbacks of the underlying BluetoothAgentServiceProvider object.
- class PairingContext {
- public:
- ~PairingContext();
-
- // Indicates whether the device is currently pairing and expecting a
- // PIN Code to be returned.
- bool ExpectingPinCode() const;
-
- // Indicates whether the device is currently pairing and expecting a
- // Passkey to be returned.
- bool ExpectingPasskey() const;
-
- // Indicates whether the device is currently pairing and expecting
- // confirmation of a displayed passkey.
- bool ExpectingConfirmation() const;
-
- // Sends the PIN code |pincode| to the remote device during pairing.
- //
- // PIN Codes are generally required for Bluetooth 2.0 and earlier devices
- // for which there is no automatic pairing or special handling.
- void SetPinCode(const std::string& pincode);
-
- // Sends the Passkey |passkey| to the remote device during pairing.
- //
- // Passkeys are generally required for Bluetooth 2.1 and later devices
- // which cannot provide input or display on their own, and don't accept
- // passkey-less pairing, and are a numeric in the range 0-999999.
- void SetPasskey(uint32 passkey);
-
- // Confirms to the remote device during pairing that a passkey provided by
- // the ConfirmPasskey() delegate call is displayed on both devices.
- void ConfirmPairing();
-
- // Rejects a pairing or connection request from a remote device, returns
- // false if there was no way to reject the pairing.
- bool RejectPairing();
-
- // Cancels a pairing or connection attempt to a remote device, returns
- // false if there was no way to cancel the pairing.
- bool CancelPairing();
-
- private:
- friend class BluetoothAdapterChromeOS;
- friend class BluetoothDeviceChromeOS;
-
- explicit PairingContext(
- device::BluetoothDevice::PairingDelegate* pairing_delegate_);
-
- // Internal method to response to the relevant callback for a RejectPairing
- // or CancelPairing call.
- bool RunPairingCallbacks(
- BluetoothAgentServiceProvider::Delegate::Status status);
-
- // UI Pairing Delegate to make method calls on, this must live as long as
- // the object capturing the PairingContext.
- device::BluetoothDevice::PairingDelegate* pairing_delegate_;
-
- // Flag to indicate whether any pairing delegate method has been called
- // during pairing. Used to determine whether we need to log the
- // "no pairing interaction" metric.
- bool pairing_delegate_used_;
-
- // During pairing these callbacks are set to those provided by method calls
- // made on the BluetoothAdapterChromeOS instance by its respective
- // BluetoothAgentServiceProvider instance, and are called by our own
- // method calls such as SetPinCode() and SetPasskey().
- PinCodeCallback pincode_callback_;
- PasskeyCallback passkey_callback_;
- ConfirmationCallback confirmation_callback_;
- };
-
// Called by dbus:: on completion of the D-Bus method call to register the
// pairing agent.
void OnRegisterAgent();
void OnRegisterAgentError(const std::string& error_name,
const std::string& error_message);
+ // Called by dbus:: on completion of the D-Bus method call to request that
+ // the pairing agent be made the default.
+ void OnRequestDefaultAgent();
+ void OnRequestDefaultAgentError(const std::string& error_name,
+ const std::string& error_message);
+
// Internal method used to locate the device object by object path
// (the devices map and BluetoothDevice methods are by address)
BluetoothDeviceChromeOS* GetDeviceWithPath(
const dbus::ObjectPath& object_path);
- // Internal method to obtain the ChromeOS BluetoothDevice object, returned in
- // |device_chromeos| and associated PairingContext, returned in
- // |pairing_context| for the device with path |object_path|.
- // Returns true on success, false if device doesn't exist or there is no
- // pairing context for it.
- bool GetDeviceAndPairingContext(const dbus::ObjectPath& object_path,
- BluetoothDeviceChromeOS** device_chromeos,
- PairingContext** pairing_context);
+ // Internal method to obtain a BluetoothPairingChromeOS object for the device
+ // with path |object_path|. Returns the existing pairing object if the device
+ // already has one (usually an outgoing connection in progress) or a new
+ // pairing object with the default pairing delegate if not. If no default
+ // pairing object exists, NULL will be returned.
+ BluetoothPairingChromeOS* GetPairing(const dbus::ObjectPath& object_path);
// Set the tracked adapter to the one in |object_path|, this object will
// subsequently operate on that adapter until it is removed.
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h
index 8098206..064b6bf 100644
--- a/device/bluetooth/bluetooth_adapter_mac.h
+++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -75,6 +75,11 @@ class BluetoothAdapterMac : public BluetoothAdapter {
IOReturn error,
bool aborted);
+ protected:
+ // BluetoothAdapter override
+ virtual void RemovePairingDelegateInternal(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE;
+
private:
friend class BluetoothAdapterFactory;
friend class BluetoothAdapterMacTest;
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index e330965..9ac7caa 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -198,6 +198,10 @@ void BluetoothAdapterMac::RemoveDiscoverySession(
MaybeStopDeviceInquiry();
}
+void BluetoothAdapterMac::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+}
+
void BluetoothAdapterMac::Init() {
ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
PollAdapter();
diff --git a/device/bluetooth/bluetooth_adapter_unittest.cc b/device/bluetooth/bluetooth_adapter_unittest.cc
new file mode 100644
index 0000000..c063bed
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -0,0 +1,187 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothDevice;
+
+namespace device {
+
+class TestBluetoothAdapter : public BluetoothAdapter {
+ public:
+ TestBluetoothAdapter() {
+ }
+
+ virtual void AddObserver(BluetoothAdapter::Observer* observer) OVERRIDE {
+ }
+
+ virtual void RemoveObserver(BluetoothAdapter::Observer* observer) OVERRIDE {
+
+ }
+
+ virtual std::string GetAddress() const OVERRIDE {
+ return "";
+ }
+
+ virtual std::string GetName() const OVERRIDE {
+ return "";
+ }
+
+ virtual void SetName(const std::string& name,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual bool IsInitialized() const OVERRIDE {
+ return false;
+ }
+
+ virtual bool IsPresent() const OVERRIDE {
+ return false;
+ }
+
+ virtual bool IsPowered() const OVERRIDE {
+ return false;
+ }
+
+ virtual void SetPowered(
+ bool powered,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual bool IsDiscoverable() const OVERRIDE {
+ return false;
+ }
+
+ virtual void SetDiscoverable(
+ bool discoverable,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual bool IsDiscovering() const OVERRIDE {
+ return false;
+ }
+
+ virtual void StartDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void StopDiscovering(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void AddDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void RemoveDiscoverySession(
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ virtual void ReadLocalOutOfBandPairingData(
+ const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ }
+
+ protected:
+ virtual ~TestBluetoothAdapter() {}
+
+ virtual void RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE {
+ }
+};
+
+class TestPairingDelegate : public BluetoothDevice::PairingDelegate {
+ public:
+ virtual void RequestPinCode(BluetoothDevice* device) OVERRIDE {}
+ virtual void RequestPasskey(BluetoothDevice* device) OVERRIDE {}
+ virtual void DisplayPinCode(BluetoothDevice* device,
+ const std::string& pincode) OVERRIDE {}
+ virtual void DisplayPasskey(BluetoothDevice* device,
+ uint32 passkey) OVERRIDE {}
+ virtual void KeysEntered(BluetoothDevice* device,
+ uint32 entered) OVERRIDE {}
+ virtual void ConfirmPasskey(BluetoothDevice* device,
+ uint32 passkey) OVERRIDE {}
+};
+
+
+TEST(BluetoothAdapterTest, NoDefaultPairingDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there is no registered pairing delegate, NULL is returned.
+ EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL);
+}
+
+TEST(BluetoothAdapterTest, OneDefaultPairingDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there is one registered pairing delegate, it is returned.
+ TestPairingDelegate delegate;
+
+ adapter->AddPairingDelegate(&delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+
+ EXPECT_EQ(&delegate, adapter->DefaultPairingDelegate());
+}
+
+TEST(BluetoothAdapterTest, SamePriorityDelegates) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there are two registered pairing delegates of the same
+ // priority, the first one registered is returned.
+ TestPairingDelegate delegate1, delegate2;
+
+ adapter->AddPairingDelegate(&delegate1,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+ adapter->AddPairingDelegate(&delegate2,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+
+ EXPECT_EQ(&delegate1, adapter->DefaultPairingDelegate());
+
+ // After unregistering the first, the second can be returned.
+ adapter->RemovePairingDelegate(&delegate1);
+
+ EXPECT_EQ(&delegate2, adapter->DefaultPairingDelegate());
+}
+
+TEST(BluetoothAdapterTest, HighestPriorityDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that when there are two registered pairing delegates, the one with
+ // the highest priority is returned.
+ TestPairingDelegate delegate1, delegate2;
+
+ adapter->AddPairingDelegate(&delegate1,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+ adapter->AddPairingDelegate(&delegate2,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ EXPECT_EQ(&delegate2, adapter->DefaultPairingDelegate());
+}
+
+TEST(BluetoothAdapterTest, UnregisterDelegate) {
+ scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter();
+
+ // Verify that after unregistering a delegate, NULL is returned.
+ TestPairingDelegate delegate;
+
+ adapter->AddPairingDelegate(&delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
+ adapter->RemovePairingDelegate(&delegate);
+
+ EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL);
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc
index e56ceae..bf0a9b7 100644
--- a/device/bluetooth/bluetooth_adapter_win.cc
+++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -150,6 +150,10 @@ void BluetoothAdapterWin::ReadLocalOutOfBandPairingData(
NOTIMPLEMENTED();
}
+void BluetoothAdapterWin::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+}
+
void BluetoothAdapterWin::AdapterStateChanged(
const BluetoothTaskManagerWin::AdapterState& state) {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h
index a017cd6..6e7382f 100644
--- a/device/bluetooth/bluetooth_adapter_win.h
+++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -72,6 +72,11 @@ class BluetoothAdapterWin : public BluetoothAdapter,
const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices)
OVERRIDE;
+ protected:
+ // BluetoothAdapter override
+ virtual void RemovePairingDelegateInternal(
+ device::BluetoothDevice::PairingDelegate* pairing_delegate) OVERRIDE;
+
private:
friend class BluetoothAdapterFactory;
friend class BluetoothAdapterWinTest;
diff --git a/device/bluetooth/bluetooth_chromeos_unittest.cc b/device/bluetooth/bluetooth_chromeos_unittest.cc
index 5576f40..e39a746 100644
--- a/device/bluetooth/bluetooth_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_chromeos_unittest.cc
@@ -15,7 +15,9 @@
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_chromeos.h"
+#include "device/bluetooth/bluetooth_pairing_chromeos.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
@@ -230,6 +232,7 @@ class BluetoothChromeOSTest : public testing::Test {
callback_count_ = 0;
error_callback_count_ = 0;
last_connect_error_ = BluetoothDevice::ERROR_UNKNOWN;
+ last_client_error_ = "";
}
virtual void TearDown() {
@@ -251,10 +254,11 @@ class BluetoothChromeOSTest : public testing::Test {
void DBusErrorCallback(const std::string& error_name,
const std::string& error_message) {
++error_callback_count_;
+ last_client_error_ = error_name;
QuitMessageLoop();
}
- void ConnectErrorCallback(enum BluetoothDevice::ConnectErrorCode error) {
+ void ConnectErrorCallback(BluetoothDevice::ConnectErrorCode error) {
++error_callback_count_;
last_connect_error_ = error;
}
@@ -338,15 +342,16 @@ class BluetoothChromeOSTest : public testing::Test {
int callback_count_;
int error_callback_count_;
enum BluetoothDevice::ConnectErrorCode last_connect_error_;
+ std::string last_client_error_;
private:
- // Some tests use a message loop since background processing is simulated;
- // break out of those loops.
- void QuitMessageLoop() {
- if (base::MessageLoop::current() &&
- base::MessageLoop::current()->is_running())
- base::MessageLoop::current()->Quit();
- }
+ // Some tests use a message loop since background processing is simulated;
+ // break out of those loops.
+ void QuitMessageLoop() {
+ if (base::MessageLoop::current() &&
+ base::MessageLoop::current()->is_running())
+ base::MessageLoop::current()->Quit();
+ }
};
TEST_F(BluetoothChromeOSTest, AlreadyPresent) {
@@ -2498,4 +2503,351 @@ TEST_F(BluetoothChromeOSTest, PairingCancelledInFlight) {
EXPECT_FALSE(device->IsPaired());
}
+TEST_F(BluetoothChromeOSTest, IncomingPairSonyHeadphones) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // The sony headphones requests that we provide a PIN code.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kSonyHeadphonesPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kSonyHeadphonesAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kSonyHeadphonesPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.request_pincode_count_);
+
+ // Set the PIN.
+ device->SetPinCode("1234");
+ message_loop.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One for paired.
+ EXPECT_EQ(1, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairPhone) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // The fake phone requests that we confirm a displayed passkey.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPhonePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kPhoneAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPhonePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_);
+ EXPECT_EQ(123456U, pairing_delegate.last_passkey_);
+
+ // Confirm the passkey.
+ device->ConfirmPairing();
+ message_loop.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One for paired.
+ EXPECT_EQ(1, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairWeirdDevice) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // The weird device requests that we provide a Passkey.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kWeirdDeviceAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.request_passkey_count_);
+
+ // Set the Passkey.
+ device->SetPasskey(1234);
+ message_loop.Run();
+
+ EXPECT_EQ(1, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+
+ // One for paired.
+ EXPECT_EQ(1, observer.device_changed_count_);
+ EXPECT_EQ(device, observer.last_device_);
+
+ EXPECT_TRUE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairSonyHeadphonesWithoutDelegate) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // The Sony Headphones requests that we provide a PIN Code, without a
+ // pairing delegate, that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kSonyHeadphonesPath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kSonyHeadphonesAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kSonyHeadphonesPath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairPhoneWithoutDelegate) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // The fake phone requests that we confirm a displayed passkey, without a
+ // pairing delegate, that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPhonePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kPhoneAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPhonePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, IncomingPairWeirdDeviceWithoutDelegate) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ // The weird device requests that we provide a displayed passkey, without a
+ // pairing delegate, that will be rejected.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kWeirdDeviceAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop.Run();
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(1, error_callback_count_);
+ EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_);
+
+ // No changes should be observer.
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+
+ // No pairing context should remain on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+}
+
+TEST_F(BluetoothChromeOSTest, RemovePairingDelegateDuringPairing) {
+ base::MessageLoop message_loop;
+ fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
+
+ GetAdapter();
+
+ TestPairingDelegate pairing_delegate;
+ adapter_->AddPairingDelegate(
+ &pairing_delegate,
+ BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+
+ // The weird device requests that we provide a Passkey.
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath));
+ BluetoothDevice* device = adapter_->GetDevice(
+ FakeBluetoothDeviceClient::kWeirdDeviceAddress);
+ ASSERT_TRUE(device != NULL);
+ ASSERT_FALSE(device->IsPaired());
+
+ TestObserver observer(adapter_);
+ adapter_->AddObserver(&observer);
+
+ fake_bluetooth_device_client_->SimulatePairing(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kWeirdDevicePath),
+ true,
+ base::Bind(&BluetoothChromeOSTest::Callback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ EXPECT_EQ(1, pairing_delegate.call_count_);
+ EXPECT_EQ(1, pairing_delegate.request_passkey_count_);
+
+ // A pairing context should now be set on the device.
+ BluetoothDeviceChromeOS* device_chromeos =
+ static_cast<BluetoothDeviceChromeOS*>(device);
+ ASSERT_TRUE(device_chromeos->GetPairing() != NULL);
+
+ // Removing the pairing delegate should remove that pairing context.
+ adapter_->RemovePairingDelegate(&pairing_delegate);
+
+ EXPECT_TRUE(device_chromeos->GetPairing() == NULL);
+
+ // Set the Passkey, this should now have no effect since the pairing has
+ // been, in-effect, cancelled
+ device->SetPasskey(1234);
+
+ EXPECT_EQ(0, callback_count_);
+ EXPECT_EQ(0, error_callback_count_);
+ EXPECT_EQ(0, observer.device_changed_count_);
+
+ EXPECT_FALSE(device->IsPaired());
+}
+
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc
index 2d43661..b76c512 100644
--- a/device/bluetooth/bluetooth_device_chromeos.cc
+++ b/device/bluetooth/bluetooth_device_chromeos.cc
@@ -14,6 +14,7 @@
#include "chromeos/dbus/dbus_thread_manager.h"
#include "dbus/bus.h"
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_pairing_chromeos.h"
#include "device/bluetooth/bluetooth_profile_chromeos.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
@@ -226,15 +227,15 @@ void BluetoothDeviceChromeOS::ProvidesServiceWithName(
}
bool BluetoothDeviceChromeOS::ExpectingPinCode() const {
- return pairing_context_.get() && pairing_context_->ExpectingPinCode();
+ return pairing_.get() && pairing_->ExpectingPinCode();
}
bool BluetoothDeviceChromeOS::ExpectingPasskey() const {
- return pairing_context_.get() && pairing_context_->ExpectingPasskey();
+ return pairing_.get() && pairing_->ExpectingPasskey();
}
bool BluetoothDeviceChromeOS::ExpectingConfirmation() const {
- return pairing_context_.get() && pairing_context_->ExpectingConfirmation();
+ return pairing_.get() && pairing_->ExpectingConfirmation();
}
void BluetoothDeviceChromeOS::Connect(
@@ -252,9 +253,7 @@ void BluetoothDeviceChromeOS::Connect(
ConnectInternal(false, callback, error_callback);
} else {
// Initiate high-security connection with pairing.
- DCHECK(!pairing_context_);
- pairing_context_.reset(
- new BluetoothAdapterChromeOS::PairingContext(pairing_delegate));
+ BeginPairing(pairing_delegate);
DBusThreadManager::Get()->GetBluetoothDeviceClient()->
Pair(object_path_,
@@ -268,31 +267,31 @@ void BluetoothDeviceChromeOS::Connect(
}
void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) {
- if (!pairing_context_.get())
+ if (!pairing_.get())
return;
- pairing_context_->SetPinCode(pincode);
+ pairing_->SetPinCode(pincode);
}
void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) {
- if (!pairing_context_.get())
+ if (!pairing_.get())
return;
- pairing_context_->SetPasskey(passkey);
+ pairing_->SetPasskey(passkey);
}
void BluetoothDeviceChromeOS::ConfirmPairing() {
- if (!pairing_context_.get())
+ if (!pairing_.get())
return;
- pairing_context_->ConfirmPairing();
+ pairing_->ConfirmPairing();
}
void BluetoothDeviceChromeOS::RejectPairing() {
- if (!pairing_context_.get())
+ if (!pairing_.get())
return;
- pairing_context_->RejectPairing();
+ pairing_->RejectPairing();
}
void BluetoothDeviceChromeOS::CancelPairing() {
@@ -300,7 +299,7 @@ void BluetoothDeviceChromeOS::CancelPairing() {
// If there is a callback in progress that we can reply to then use that
// to cancel the current pairing request.
- if (pairing_context_.get() && pairing_context_->CancelPairing())
+ if (pairing_.get() && pairing_->CancelPairing())
canceled = true;
// If not we have to send an explicit CancelPairing() to the device instead.
@@ -313,14 +312,13 @@ void BluetoothDeviceChromeOS::CancelPairing() {
base::Bind(&base::DoNothing),
base::Bind(&BluetoothDeviceChromeOS::OnCancelPairingError,
weak_ptr_factory_.GetWeakPtr()));
- canceled = true;
}
// Since there is no callback to this method it's possible that the pairing
// delegate is going to be freed before things complete (indeed it's
// documented that this is the method you should call while freeing the
// pairing delegate), so clear our the context holding on to it.
- pairing_context_.reset();
+ EndPairing();
}
void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback,
@@ -395,6 +393,21 @@ void BluetoothDeviceChromeOS::ClearOutOfBandPairingData(
error_callback.Run();
}
+BluetoothPairingChromeOS* BluetoothDeviceChromeOS::BeginPairing(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ DCHECK(!pairing_);
+ pairing_.reset(new BluetoothPairingChromeOS(this, pairing_delegate));
+ return pairing_.get();
+}
+
+void BluetoothDeviceChromeOS::EndPairing() {
+ pairing_.reset();
+}
+
+BluetoothPairingChromeOS* BluetoothDeviceChromeOS::GetPairing() const {
+ return pairing_.get();
+}
+
void BluetoothDeviceChromeOS::ConnectInternal(
bool after_pairing,
const base::Closure& callback,
@@ -466,7 +479,7 @@ void BluetoothDeviceChromeOS::OnPair(
const ConnectErrorCallback& error_callback) {
VLOG(1) << object_path_.value() << ": Paired";
- pairing_context_.reset();
+ EndPairing();
SetTrusted();
ConnectInternal(true, callback, error_callback);
@@ -485,7 +498,7 @@ void BluetoothDeviceChromeOS::OnPairError(
VLOG(1) << object_path_.value() << ": " << num_connecting_calls_
<< " still in progress";
- pairing_context_.reset();
+ EndPairing();
// Determine the error code from error_name.
ConnectErrorCode error_code = ERROR_UNKNOWN;
diff --git a/device/bluetooth/bluetooth_device_chromeos.h b/device/bluetooth/bluetooth_device_chromeos.h
index e2f2997..797f66e 100644
--- a/device/bluetooth/bluetooth_device_chromeos.h
+++ b/device/bluetooth/bluetooth_device_chromeos.h
@@ -11,11 +11,13 @@
#include "base/memory/weak_ptr.h"
#include "chromeos/dbus/bluetooth_device_client.h"
#include "dbus/object_path.h"
-#include "device/bluetooth/bluetooth_adapter_chromeos.h"
#include "device/bluetooth/bluetooth_device.h"
namespace chromeos {
+class BluetoothAdapterChromeOS;
+class BluetoothPairingChromeOS;
+
// The BluetoothDeviceChromeOS class implements BluetoothDevice for the
// Chrome OS platform.
class BluetoothDeviceChromeOS
@@ -69,6 +71,19 @@ class BluetoothDeviceChromeOS
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
+ // Creates a pairing object with the given delegate |pairing_delegate| and
+ // establishes it as the pairing context for this device. All pairing-related
+ // method calls will be forwarded to this object until it is released.
+ BluetoothPairingChromeOS* BeginPairing(
+ BluetoothDevice::PairingDelegate* pairing_delegate);
+
+ // Releases the current pairing object, any pairing-related method calls will
+ // be ignored.
+ void EndPairing();
+
+ // Returns the current pairing object or NULL if no pairing is in progress.
+ BluetoothPairingChromeOS* GetPairing() const;
+
protected:
// BluetoothDevice override
virtual std::string GetDeviceName() const OVERRIDE;
@@ -135,7 +150,7 @@ class BluetoothDeviceChromeOS
const std::string& error_name,
const std::string& error_message);
- // Return the object path of the device; used by BluetoothAdapterChromeOS
+ // Returns the object path of the device; used by BluetoothAdapterChromeOS
const dbus::ObjectPath& object_path() const { return object_path_; }
// The adapter that owns this device instance.
@@ -150,9 +165,7 @@ class BluetoothDeviceChromeOS
// During pairing this is set to an object that we don't own, but on which
// we can make method calls to request, display or confirm PIN Codes and
// Passkeys. Generally it is the object that owns this one.
- PairingDelegate* pairing_delegate_;
-
- scoped_ptr<BluetoothAdapterChromeOS::PairingContext> pairing_context_;
+ scoped_ptr<BluetoothPairingChromeOS> pairing_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
diff --git a/device/bluetooth/bluetooth_pairing_chromeos.cc b/device/bluetooth/bluetooth_pairing_chromeos.cc
new file mode 100644
index 0000000..d3b826d
--- /dev/null
+++ b/device/bluetooth/bluetooth_pairing_chromeos.cc
@@ -0,0 +1,248 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_pairing_chromeos.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_device_chromeos.h"
+
+using device::BluetoothDevice;
+
+namespace {
+
+// Histogram enumerations for pairing methods.
+enum UMAPairingMethod {
+ UMA_PAIRING_METHOD_NONE,
+ UMA_PAIRING_METHOD_REQUEST_PINCODE,
+ UMA_PAIRING_METHOD_REQUEST_PASSKEY,
+ UMA_PAIRING_METHOD_DISPLAY_PINCODE,
+ UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
+ UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
+ // NOTE: Add new pairing methods immediately above this line. Make sure to
+ // update the enum list in tools/histogram/histograms.xml accordingly.
+ UMA_PAIRING_METHOD_COUNT
+};
+
+} // namespace
+
+namespace chromeos {
+
+BluetoothPairingChromeOS::BluetoothPairingChromeOS(
+ BluetoothDeviceChromeOS* device,
+ BluetoothDevice::PairingDelegate* pairing_delegate)
+ : device_(device),
+ pairing_delegate_(pairing_delegate),
+ pairing_delegate_used_(false) {
+ VLOG(1) << "Created BluetoothPairingChromeOS for "
+ << device_->GetAddress();
+}
+
+BluetoothPairingChromeOS::~BluetoothPairingChromeOS() {
+ VLOG(1) << "Destroying BluetoothPairingChromeOS for "
+ << device_->GetAddress();
+
+ if (!pairing_delegate_used_) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_NONE,
+ UMA_PAIRING_METHOD_COUNT);
+ }
+
+ if (!pincode_callback_.is_null()) {
+ pincode_callback_.Run(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED, "");
+ }
+
+ if (!passkey_callback_.is_null()) {
+ passkey_callback_.Run(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED, 0);
+ }
+
+ if (!confirmation_callback_.is_null()) {
+ confirmation_callback_.Run(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED);
+ }
+
+ pairing_delegate_ = NULL;
+}
+
+void BluetoothPairingChromeOS::RequestPinCode(
+ const BluetoothAgentServiceProvider::Delegate::PinCodeCallback& callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_REQUEST_PINCODE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(pincode_callback_.is_null());
+ pincode_callback_ = callback;
+ pairing_delegate_->RequestPinCode(device_);
+ pairing_delegate_used_ = true;
+}
+
+bool BluetoothPairingChromeOS::ExpectingPinCode() const {
+ return !pincode_callback_.is_null();
+}
+
+void BluetoothPairingChromeOS::SetPinCode(const std::string& pincode) {
+ if (pincode_callback_.is_null())
+ return;
+
+ pincode_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS,
+ pincode);
+ pincode_callback_.Reset();
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::DisplayPinCode(const std::string& pincode) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_DISPLAY_PINCODE,
+ UMA_PAIRING_METHOD_COUNT);
+
+ pairing_delegate_->DisplayPinCode(device_, pincode);
+ pairing_delegate_used_ = true;
+
+ // If this is not an outgoing connection to the device, the pairing context
+ // needs to be cleaned up again as there's no reliable indication of
+ // completion of incoming pairing.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::RequestPasskey(
+ const BluetoothAgentServiceProvider::Delegate::PasskeyCallback& callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_REQUEST_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(passkey_callback_.is_null());
+ passkey_callback_ = callback;
+ pairing_delegate_->RequestPasskey(device_);
+ pairing_delegate_used_ = true;
+}
+
+bool BluetoothPairingChromeOS::ExpectingPasskey() const {
+ return !passkey_callback_.is_null();
+}
+
+void BluetoothPairingChromeOS::SetPasskey(uint32 passkey) {
+ if (passkey_callback_.is_null())
+ return;
+
+ passkey_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS,
+ passkey);
+ passkey_callback_.Reset();
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::DisplayPasskey(uint32 passkey) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_DISPLAY_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+
+ pairing_delegate_->DisplayPasskey(device_, passkey);
+ pairing_delegate_used_ = true;
+
+ // If this is not an outgoing connection to the device, the pairing context
+ // needs to be cleaned up again as there's no reliable indication of
+ // completion of incoming pairing.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+void BluetoothPairingChromeOS::KeysEntered(uint16 entered) {
+ pairing_delegate_->KeysEntered(device_, entered);
+ pairing_delegate_used_ = true;
+}
+
+void BluetoothPairingChromeOS::RequestConfirmation(
+ uint32 passkey,
+ const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback&
+ callback) {
+ UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod",
+ UMA_PAIRING_METHOD_CONFIRM_PASSKEY,
+ UMA_PAIRING_METHOD_COUNT);
+
+ DCHECK(confirmation_callback_.is_null());
+ confirmation_callback_ = callback;
+ pairing_delegate_->ConfirmPasskey(device_, passkey);
+ pairing_delegate_used_ = true;
+}
+
+bool BluetoothPairingChromeOS::ExpectingConfirmation() const {
+ return !confirmation_callback_.is_null();
+}
+
+void BluetoothPairingChromeOS::ConfirmPairing() {
+ if (confirmation_callback_.is_null())
+ return;
+
+ confirmation_callback_.Run(BluetoothAgentServiceProvider::Delegate::SUCCESS);
+ confirmation_callback_.Reset();
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+}
+
+bool BluetoothPairingChromeOS::RejectPairing() {
+ return RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::REJECTED);
+}
+
+bool BluetoothPairingChromeOS::CancelPairing() {
+ return RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::CANCELLED);
+}
+
+BluetoothDevice::PairingDelegate*
+BluetoothPairingChromeOS::GetPairingDelegate() const {
+ return pairing_delegate_;
+}
+
+bool BluetoothPairingChromeOS::RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::Status status) {
+ pairing_delegate_used_ = true;
+
+ bool callback_run = false;
+ if (!pincode_callback_.is_null()) {
+ pincode_callback_.Run(status, "");
+ pincode_callback_.Reset();
+ callback_run = true;
+ }
+
+ if (!passkey_callback_.is_null()) {
+ passkey_callback_.Run(status, 0);
+ passkey_callback_.Reset();
+ callback_run = true;
+ }
+
+ if (!confirmation_callback_.is_null()) {
+ confirmation_callback_.Run(status);
+ confirmation_callback_.Reset();
+ callback_run = true;
+ }
+
+ // If this is not an outgoing connection to the device, clean up the pairing
+ // context since the pairing is done. The outgoing connection case is cleaned
+ // up in the callback for the underlying Pair() call.
+ if (!device_->IsConnecting())
+ device_->EndPairing();
+
+ return callback_run;
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_pairing_chromeos.h b/device/bluetooth/bluetooth_pairing_chromeos.h
new file mode 100644
index 0000000..6772497
--- /dev/null
+++ b/device/bluetooth/bluetooth_pairing_chromeos.h
@@ -0,0 +1,134 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_PAIRING_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_PAIRING_CHROMEOS_H_
+
+#include "chromeos/dbus/bluetooth_agent_service_provider.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace chromeos {
+
+class BluetoothDeviceChromeOS;
+
+// The BluetoothPairingChromeOS class encapsulates the logic for an individual
+// device pairing, acting as a bridge between BluetoothAdapterChromeOS which
+// communicates with the underlying Controller and Host Subsystem, and
+// BluetoothDeviceChromeOS which presents the pairing logic to the application.
+class BluetoothPairingChromeOS {
+ public:
+ BluetoothPairingChromeOS(
+ BluetoothDeviceChromeOS* device,
+ device::BluetoothDevice::PairingDelegate* pairing_delegate);
+ ~BluetoothPairingChromeOS();
+
+ // Indicates whether the device is currently pairing and expecting a
+ // Passkey to be returned.
+ bool ExpectingPasskey() const;
+
+ // Indicates whether the device is currently pairing and expecting
+ // confirmation of a displayed passkey.
+ bool ExpectingConfirmation() const;
+
+ // Requests a PIN code for the current device from the current pairing
+ // delegate, the SetPinCode(), RejectPairing() and CancelPairing() method
+ // calls on this object are translated into the appropriate response to
+ // |callback|.
+ void RequestPinCode(
+ const BluetoothAgentServiceProvider::Delegate::PinCodeCallback& callback);
+
+ // Indicates whether the device is currently pairing and expecting a
+ // PIN Code to be returned.
+ bool ExpectingPinCode() const;
+
+ // Sends the PIN code |pincode| to the remote device during pairing.
+ //
+ // PIN Codes are generally required for Bluetooth 2.0 and earlier devices
+ // for which there is no automatic pairing or special handling.
+ void SetPinCode(const std::string& pincode);
+
+ // Requests a PIN code for the current device be displayed by the current
+ // pairing delegate. No response is expected from the delegate.
+ void DisplayPinCode(const std::string& pincode);
+
+ // Requests a Passkey for the current device from the current pairing
+ // delegate, the SetPasskey(), RejectPairing() and CancelPairing() method
+ // calls on this object are translated into the appropriate response to
+ // |callback|.
+ void RequestPasskey(
+ const BluetoothAgentServiceProvider::Delegate::PasskeyCallback& callback);
+
+ // Sends the Passkey |passkey| to the remote device during pairing.
+ //
+ // Passkeys are generally required for Bluetooth 2.1 and later devices
+ // which cannot provide input or display on their own, and don't accept
+ // passkey-less pairing, and are a numeric in the range 0-999999.
+ void SetPasskey(uint32 passkey);
+
+ // Requests a Passkey for the current device be displayed by the current
+ // pairing delegate. No response is expected from the delegate.
+ void DisplayPasskey(uint32 passkey);
+
+ // Informs the current pairing delegate that |entered| keys have been
+ // provided to the remote device since the DisplayPasskey() call. No
+ // response is expected from the delegate.
+ void KeysEntered(uint16 entered);
+
+ // Requests confirmation that |passkey| is displayed on the current device
+ // from the current pairing delegate. The ConfirmPairing(), RejectPairing()
+ // and CancelPairing() method calls on this object are translated into the
+ // appropriate response to |callback|.
+ void RequestConfirmation(
+ uint32 passkey,
+ const BluetoothAgentServiceProvider::Delegate::ConfirmationCallback&
+ callback);
+
+ // Confirms to the remote device during pairing that a passkey provided by
+ // the ConfirmPasskey() delegate call is displayed on both devices.
+ void ConfirmPairing();
+
+ // Rejects a pairing or connection request from a remote device, returns
+ // false if there was no way to reject the pairing.
+ bool RejectPairing();
+
+ // Cancels a pairing or connection attempt to a remote device, returns
+ // false if there was no way to cancel the pairing.
+ bool CancelPairing();
+
+ // Returns the pairing delegate being used by this pairing object.
+ device::BluetoothDevice::PairingDelegate* GetPairingDelegate() const;
+
+ private:
+ // Internal method to respond to the relevant callback for a RejectPairing
+ // or CancelPairing call.
+ bool RunPairingCallbacks(
+ BluetoothAgentServiceProvider::Delegate::Status status);
+
+ // The underlying BluetoothDeviceChromeOS that owns this pairing context.
+ BluetoothDeviceChromeOS* device_;
+
+ // UI Pairing Delegate to make method calls on, this must live as long as
+ // the object capturing the PairingContext.
+ device::BluetoothDevice::PairingDelegate* pairing_delegate_;
+
+ // Flag to indicate whether any pairing delegate method has been called
+ // during pairing. Used to determine whether we need to log the
+ // "no pairing interaction" metric.
+ bool pairing_delegate_used_;
+
+ // During pairing these callbacks are set to those provided by method calls
+ // made on the BluetoothAdapterChromeOS instance by its respective
+ // BluetoothAgentServiceProvider instance, and are called by our own
+ // method calls such as SetPinCode() and SetPasskey().
+ BluetoothAgentServiceProvider::Delegate::PinCodeCallback pincode_callback_;
+ BluetoothAgentServiceProvider::Delegate::PasskeyCallback passkey_callback_;
+ BluetoothAgentServiceProvider::Delegate::ConfirmationCallback
+ confirmation_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothPairingChromeOS);
+};
+
+} // namespace chromeos
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_PAIRING_CHROMEOS_H_
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h
index 1e1cb35..56647fe 100644
--- a/device/bluetooth/test/mock_bluetooth_adapter.h
+++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -66,6 +66,13 @@ class MockBluetoothAdapter : public BluetoothAdapter {
ReadLocalOutOfBandPairingData,
void(const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback));
+ MOCK_METHOD2(AddPairingDelegate,
+ void(BluetoothDevice::PairingDelegate* pairing_delegate,
+ enum PairingDelegatePriority priority));
+ MOCK_METHOD1(RemovePairingDelegate,
+ void(BluetoothDevice::PairingDelegate* pairing_delegate));
+ MOCK_METHOD0(DefaultPairingDelegate, BluetoothDevice::PairingDelegate*());
+
protected:
MOCK_METHOD2(AddDiscoverySession,
void(const base::Closure& callback,
@@ -74,6 +81,9 @@ class MockBluetoothAdapter : public BluetoothAdapter {
void(const base::Closure& callback,
const ErrorCallback& error_callback));
virtual ~MockBluetoothAdapter();
+
+ MOCK_METHOD1(RemovePairingDelegateInternal,
+ void(BluetoothDevice::PairingDelegate* pairing_delegate));
};
} // namespace device
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index 268b270..63c0a82 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -23,6 +23,7 @@
],
'sources': [
'bluetooth/bluetooth_adapter_mac_unittest.mm',
+ 'bluetooth/bluetooth_adapter_unittest.cc',
'bluetooth/bluetooth_adapter_win_unittest.cc',
'bluetooth/bluetooth_device_win_unittest.cc',
'bluetooth/bluetooth_chromeos_unittest.cc',