summaryrefslogtreecommitdiffstats
path: root/device/bluetooth
diff options
context:
space:
mode:
authorrpaquay@chromium.org <rpaquay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-28 00:51:49 +0000
committerrpaquay@chromium.org <rpaquay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-28 00:51:49 +0000
commit2ede7a239f238510b9c2e8b83869d75f72f63305 (patch)
treeca49c15ded8c82e6f7bd83d8b9e60d6aa4fa805c /device/bluetooth
parenta136eaacb0921973b87648b64adff33aa07ebbba (diff)
downloadchromium_src-2ede7a239f238510b9c2e8b83869d75f72f63305.zip
chromium_src-2ede7a239f238510b9c2e8b83869d75f72f63305.tar.gz
chromium_src-2ede7a239f238510b9c2e8b83869d75f72f63305.tar.bz2
Add Bluetooth LE enumeration to adapter polling.
Initial change: During adapter polling, the list of Bluetooth LE devices is enumerated as the same time as the Classic devices. They are all reported in a single collection which ends up being exposed to the JavaScript API. For BLE devices, we currently only initialize the "name" and "address" fields of "DeviceInfo". BUG=388016 Review URL: https://codereview.chromium.org/349373002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@280470 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/bluetooth')
-rw-r--r--device/bluetooth/bluetooth.gyp2
-rw-r--r--device/bluetooth/bluetooth_low_energy_win.cc463
-rw-r--r--device/bluetooth/bluetooth_low_energy_win.h78
-rw-r--r--device/bluetooth/bluetooth_low_energy_win_unittest.cc50
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.cc51
5 files changed, 629 insertions, 15 deletions
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index 4d206ec..25c6753 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -63,6 +63,8 @@
'bluetooth_init_win.h',
'bluetooth_l2cap_channel_mac.mm',
'bluetooth_l2cap_channel_mac.h',
+ 'bluetooth_low_energy_win.cc',
+ 'bluetooth_low_energy_win.h',
'bluetooth_pairing_chromeos.cc',
'bluetooth_pairing_chromeos.h',
'bluetooth_remote_gatt_characteristic_chromeos.cc',
diff --git a/device/bluetooth/bluetooth_low_energy_win.cc b/device/bluetooth/bluetooth_low_energy_win.cc
new file mode 100644
index 0000000..8d1790e
--- /dev/null
+++ b/device/bluetooth/bluetooth_low_energy_win.cc
@@ -0,0 +1,463 @@
+// 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_low_energy_win.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+const char kPlatformNotSupported[] =
+ "Bluetooth Low energy is only supported on Windows 8 and later.";
+const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices.";
+const char kDeviceInfoError[] =
+ "Error retrieving Bluetooth LE device information.";
+const char kDeviceAddressError[] =
+ "Device instance ID value does not seem to contain a Bluetooth Adapter "
+ "address.";
+const char kInvalidBluetoothAddress[] = "Bluetooth address format is invalid.";
+
+// Like ScopedHandle but for HDEVINFO. Only use this on HDEVINFO returned from
+// SetupDiGetClassDevs.
+class DeviceInfoSetTraits {
+ public:
+ typedef HDEVINFO Handle;
+
+ static bool CloseHandle(HDEVINFO handle) {
+ return ::SetupDiDestroyDeviceInfoList(handle) != FALSE;
+ }
+
+ static bool IsHandleValid(HDEVINFO handle) {
+ return handle != INVALID_HANDLE_VALUE;
+ }
+
+ static HDEVINFO NullHandle() { return INVALID_HANDLE_VALUE; }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DeviceInfoSetTraits);
+};
+
+typedef base::win::GenericScopedHandle<DeviceInfoSetTraits,
+ base::win::VerifierTraits>
+ ScopedDeviceInfoSetHandle;
+
+bool StringToBluetoothAddress(const std::string& value,
+ BLUETOOTH_ADDRESS* btha,
+ std::string* error) {
+ if (value.length() != 6 * 2) {
+ *error = kInvalidBluetoothAddress;
+ return false;
+ }
+
+ int buffer[6];
+ int result = sscanf_s(value.c_str(),
+ "%02X%02X%02X%02X%02X%02X",
+ &buffer[5],
+ &buffer[4],
+ &buffer[3],
+ &buffer[2],
+ &buffer[1],
+ &buffer[0]);
+ if (result != 6) {
+ *error = kInvalidBluetoothAddress;
+ return false;
+ }
+
+ ZeroMemory(btha, sizeof(*btha));
+ btha->rgBytes[0] = buffer[0];
+ btha->rgBytes[1] = buffer[1];
+ btha->rgBytes[2] = buffer[2];
+ btha->rgBytes[3] = buffer[3];
+ btha->rgBytes[4] = buffer[4];
+ btha->rgBytes[5] = buffer[5];
+ return true;
+}
+
+std::string FormatBluetoothError(const char* message, HRESULT hr) {
+ std::ostringstream string_stream;
+ string_stream << message;
+ if (FAILED(hr))
+ string_stream << logging::SystemErrorCodeToString(hr);
+ return string_stream.str();
+}
+
+bool CheckInsufficientBuffer(bool success,
+ const char* message,
+ std::string* error) {
+ if (success) {
+ *error = FormatBluetoothError(message, S_OK);
+ return false;
+ }
+
+ HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
+ if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+ *error = FormatBluetoothError(message, hr);
+ return false;
+ }
+
+ return true;
+}
+
+bool CheckSuccess(HRESULT hr, const char* message, std::string* error) {
+ if (FAILED(hr)) {
+ *error = FormatBluetoothError(message, hr);
+ return false;
+ }
+
+ return true;
+}
+
+bool CheckExpectedLength(size_t actual_length,
+ size_t expected_length,
+ const char* message,
+ std::string* error) {
+ if (actual_length != expected_length) {
+ *error = FormatBluetoothError(message, E_FAIL);
+ return false;
+ }
+
+ return true;
+}
+
+// Represents a device registry property value
+class DeviceRegistryPropertyValue {
+ public:
+ static scoped_ptr<DeviceRegistryPropertyValue>
+ Create(DWORD property_type, scoped_ptr<UINT8[]> value, size_t value_size) {
+ if (property_type == REG_SZ) {
+ // Ensure string is zero terminated.
+ CHECK_GE(value_size, 1u);
+ WCHAR* value_string = reinterpret_cast<WCHAR*>(value.get());
+ value_string[value_size - 1] = 0;
+ }
+ return scoped_ptr<DeviceRegistryPropertyValue>(
+ new DeviceRegistryPropertyValue(
+ property_type, value.Pass(), value_size));
+ }
+
+ bool AsString(std::string* value, std::string* error) {
+ if (property_type_ != REG_SZ) {
+ *error = "Property is not a string";
+ return false;
+ }
+
+ WCHAR* value_string = reinterpret_cast<WCHAR*>(value_.get());
+ *value = base::SysWideToUTF8(value_string);
+ return true;
+ }
+
+ private:
+ DeviceRegistryPropertyValue(DWORD property_type,
+ scoped_ptr<UINT8[]> value,
+ size_t value_size)
+ : property_type_(property_type),
+ value_(value.Pass()),
+ value_size_(value_size) {}
+
+ DWORD property_type_;
+ scoped_ptr<UINT8[]> value_;
+ size_t value_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceRegistryPropertyValue);
+};
+
+bool CollectBluetoothLowEnergyDeviceRegistryProperty(
+ const ScopedDeviceInfoSetHandle& device_info_handle,
+ PSP_DEVINFO_DATA device_info_data,
+ DWORD property_id,
+ scoped_ptr<DeviceRegistryPropertyValue>* value,
+ std::string* error) {
+ ULONG required_length = 0;
+ BOOL success = SetupDiGetDeviceRegistryProperty(device_info_handle,
+ device_info_data,
+ property_id,
+ NULL,
+ NULL,
+ 0,
+ &required_length);
+ if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error))
+ return false;
+
+ scoped_ptr<UINT8[]> property_value(new UINT8[required_length]);
+ ULONG actual_length = required_length;
+ DWORD property_type;
+ success = SetupDiGetDeviceRegistryProperty(device_info_handle,
+ device_info_data,
+ property_id,
+ &property_type,
+ property_value.get(),
+ actual_length,
+ &required_length);
+ if (!CheckSuccess(!!success, kDeviceInfoError, error))
+ return false;
+ if (!CheckExpectedLength(
+ actual_length, required_length, kDeviceInfoError, error))
+ return false;
+
+ (*value) = DeviceRegistryPropertyValue::Create(
+ property_type, property_value.Pass(), actual_length).Pass();
+ return true;
+}
+
+bool CollectBluetoothLowEnergyDeviceInstanceId(
+ const ScopedDeviceInfoSetHandle& device_info_handle,
+ PSP_DEVINFO_DATA device_info_data,
+ scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info,
+ std::string* error) {
+ ULONG required_length = 0;
+ BOOL success = SetupDiGetDeviceInstanceId(
+ device_info_handle, device_info_data, NULL, 0, &required_length);
+ if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error))
+ return false;
+
+ scoped_ptr<WCHAR[]> instance_id(new WCHAR[required_length]);
+ ULONG actual_length = required_length;
+ success = SetupDiGetDeviceInstanceId(device_info_handle,
+ device_info_data,
+ instance_id.get(),
+ actual_length,
+ &required_length);
+ if (!CheckSuccess(!!success, kDeviceInfoError, error))
+ return false;
+ if (!CheckExpectedLength(
+ actual_length, required_length, kDeviceInfoError, error)) {
+ return false;
+ }
+
+ if (actual_length >= 1) {
+ // Ensure string is zero terminated.
+ instance_id.get()[actual_length - 1] = 0;
+ device_info->id = base::SysWideToUTF8(instance_id.get());
+ }
+ return true;
+}
+
+bool CollectDeviceFriendlyName(
+ const ScopedDeviceInfoSetHandle& device_info_handle,
+ PSP_DEVINFO_DATA device_info_data,
+ scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info,
+ std::string* error) {
+ scoped_ptr<DeviceRegistryPropertyValue> property_value;
+ if (!CollectBluetoothLowEnergyDeviceRegistryProperty(device_info_handle,
+ device_info_data,
+ SPDRP_FRIENDLYNAME,
+ &property_value,
+ error)) {
+ return false;
+ }
+
+ if (!property_value->AsString(&device_info->friendly_name, error)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ExtractBluetoothAddressFromDeviceInstanceId(const std::string& instance_id,
+ BLUETOOTH_ADDRESS* btha,
+ std::string* error) {
+ size_t start = instance_id.find("_");
+ if (start == std::string::npos) {
+ *error = kDeviceAddressError;
+ return false;
+ }
+ size_t end = instance_id.find("\\", start);
+ if (end == std::string::npos) {
+ *error = kDeviceAddressError;
+ return false;
+ }
+
+ start++;
+ std::string address = instance_id.substr(start, end - start);
+ if (!StringToBluetoothAddress(address, btha, error))
+ return false;
+
+ return true;
+}
+
+bool CollectBluetoothLowEnergyDeviceAddress(
+ const ScopedDeviceInfoSetHandle& device_info_handle,
+ PSP_DEVINFO_DATA device_info_data,
+ scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info,
+ std::string* error) {
+ // TODO(rpaquay): We exctract the bluetooth device address from the device
+ // instance ID string, as we did not find a more formal API for retrieving the
+ // bluetooth address of a Bluetooth Low Energy device.
+ // An Bluetooth device instance ID has the following format (under Win8+):
+ // BTHLE\DEV_BC6A29AB5FB0\8&31038925&0&BC6A29AB5FB0
+ return ExtractBluetoothAddressFromDeviceInstanceId(
+ device_info->id, &device_info->address, error);
+}
+
+bool CollectBluetoothLowEnergyDeviceInfo(
+ const ScopedDeviceInfoSetHandle& device_info_handle,
+ PSP_DEVICE_INTERFACE_DATA device_interface_data,
+ scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info,
+ std::string* error) {
+ // Retrieve required # of bytes for interface details
+ ULONG required_length = 0;
+ BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle,
+ device_interface_data,
+ NULL,
+ 0,
+ &required_length,
+ NULL);
+ if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error))
+ return false;
+
+ scoped_ptr<UINT8[]> interface_data(new UINT8[required_length]);
+ ZeroMemory(interface_data.get(), required_length);
+
+ PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data =
+ reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(interface_data.get());
+ device_interface_detail_data->cbSize =
+ sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+
+ SP_DEVINFO_DATA device_info_data = {0};
+ device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
+
+ ULONG actual_length = required_length;
+ success = SetupDiGetDeviceInterfaceDetail(device_info_handle,
+ device_interface_data,
+ device_interface_detail_data,
+ actual_length,
+ &required_length,
+ &device_info_data);
+ if (!CheckSuccess(!!success, kDeviceInfoError, error))
+ return false;
+ if (!CheckExpectedLength(
+ actual_length, required_length, kDeviceInfoError, error))
+ return false;
+
+ scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result(
+ new device::win::BluetoothLowEnergyDeviceInfo());
+ result->path =
+ base::FilePath(std::wstring(device_interface_detail_data->DevicePath));
+ if (!CollectBluetoothLowEnergyDeviceInstanceId(
+ device_info_handle, &device_info_data, result, error)) {
+ return false;
+ }
+ if (!CollectDeviceFriendlyName(
+ device_info_handle, &device_info_data, result, error)) {
+ return false;
+ }
+ if (!CollectBluetoothLowEnergyDeviceAddress(
+ device_info_handle, &device_info_data, result, error)) {
+ return false;
+ }
+ (*device_info) = result.Pass();
+ return true;
+}
+
+enum DeviceInfoResult { kOk, kError, kNoMoreDevices };
+
+DeviceInfoResult EnumerateSingleBluetoothLowEnergyDevice(
+ const ScopedDeviceInfoSetHandle& device_info_handle,
+ DWORD device_index,
+ scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info,
+ std::string* error) {
+ // Enumerate device of LE_DEVICE interface class
+ GUID BluetoothInterfaceGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE;
+ SP_DEVICE_INTERFACE_DATA device_interface_data = {0};
+ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ BOOL success = ::SetupDiEnumDeviceInterfaces(device_info_handle,
+ NULL,
+ &BluetoothInterfaceGUID,
+ device_index,
+ &device_interface_data);
+ if (!success) {
+ HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
+ if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) {
+ return kNoMoreDevices;
+ }
+ *error = FormatBluetoothError(kDeviceInfoError, hr);
+ return kError;
+ }
+
+ if (!CollectBluetoothLowEnergyDeviceInfo(
+ device_info_handle, &device_interface_data, device_info, error))
+ return kError;
+
+ return kOk;
+}
+
+// Opens a Device Info Set that can be used to enumerate Bluetooth LE devices
+// present on the machine.
+HRESULT OpenBluetoothLowEnergyDevices(ScopedDeviceInfoSetHandle* handle) {
+ GUID BluetoothClassGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE;
+ ScopedDeviceInfoSetHandle result(SetupDiGetClassDevs(
+ &BluetoothClassGUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
+ if (!result.IsValid()) {
+ return HRESULT_FROM_WIN32(::GetLastError());
+ }
+
+ (*handle) = result.Pass();
+ return S_OK;
+}
+
+// Opens a Device Info Set that can be used to enumerate Bluetooth LE devices
+// exposing a service GUID.
+HRESULT OpenBluetoothLowEnergyService(const GUID& service_guid,
+ ScopedDeviceInfoSetHandle* handle) {
+ ScopedDeviceInfoSetHandle result(SetupDiGetClassDevs(
+ &service_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
+ if (!result.IsValid()) {
+ return HRESULT_FROM_WIN32(::GetLastError());
+ }
+
+ (*handle) = result.Pass();
+ return S_OK;
+}
+
+} // namespace
+
+namespace device {
+namespace win {
+
+bool IsBluetoothLowEnergySupported() {
+ return base::win::GetVersion() >= base::win::VERSION_WIN8;
+}
+
+bool EnumerateKnownBluetoothLowEnergyDevices(
+ ScopedVector<BluetoothLowEnergyDeviceInfo>* devices,
+ std::string* error) {
+ if (!IsBluetoothLowEnergySupported()) {
+ *error = kPlatformNotSupported;
+ return false;
+ }
+
+ ScopedDeviceInfoSetHandle info_set_handle;
+ HRESULT hr = OpenBluetoothLowEnergyDevices(&info_set_handle);
+ if (FAILED(hr)) {
+ *error = FormatBluetoothError(kDeviceEnumError, hr);
+ return false;
+ }
+
+ for (DWORD i = 0;; ++i) {
+ scoped_ptr<BluetoothLowEnergyDeviceInfo> device_info;
+ DeviceInfoResult result = EnumerateSingleBluetoothLowEnergyDevice(
+ info_set_handle, i, &device_info, error);
+ switch (result) {
+ case kNoMoreDevices:
+ return true;
+ case kError:
+ return false;
+ case kOk:
+ devices->push_back(device_info.release());
+ }
+ }
+}
+
+bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting(
+ const std::string& instance_id,
+ BLUETOOTH_ADDRESS* btha,
+ std::string* error) {
+ return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error);
+}
+
+} // namespace win
+} // namespace device
diff --git a/device/bluetooth/bluetooth_low_energy_win.h b/device/bluetooth/bluetooth_low_energy_win.h
new file mode 100644
index 0000000..6c997e9
--- /dev/null
+++ b/device/bluetooth/bluetooth_low_energy_win.h
@@ -0,0 +1,78 @@
+// 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_LOW_ENERGY_WIN_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_WIN_H_
+
+#include <windows.h>
+#include <setupapi.h>
+// #include <bthledef.h>
+// TODO(rpaquay):
+// bthledef.h from Win8 SDK has a couple of issues when used in a Win32 app:
+// * line 420: usage of "pragma pop" instead of "pragma warning(pop)"
+// * line 349: no CALLBACK modifier in the definition of
+// PFNBLUETOOTH_GATT_EVENT_CALLBACK.
+//
+// So, we duplicate the definitions we need and prevent the build from including
+// the content of bthledef.h.
+#ifndef __BTHLEDEF_H__
+#define __BTHLEDEF_H__
+
+//
+// Bluetooth LE device interface GUID
+//
+// {781aee18-7733-4ce4-adb0-91f41c67b592}
+DEFINE_GUID(GUID_BLUETOOTHLE_DEVICE_INTERFACE,
+ 0x781aee18,
+ 0x7733,
+ 0x4ce4,
+ 0xad,
+ 0xd0,
+ 0x91,
+ 0xf4,
+ 0x1c,
+ 0x67,
+ 0xb5,
+ 0x92);
+
+#endif // __BTHLEDEF_H__
+#include <bluetoothapis.h>
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_vector.h"
+#include "base/win/scoped_handle.h"
+
+namespace device {
+namespace win {
+
+// Returns true only on Windows platforms supporting Bluetooth Low Energy.
+bool IsBluetoothLowEnergySupported();
+
+struct BluetoothLowEnergyDeviceInfo {
+ BluetoothLowEnergyDeviceInfo() { address.ullLong = BLUETOOTH_NULL_ADDRESS; }
+
+ base::FilePath path;
+ std::string id;
+ std::string friendly_name;
+ BLUETOOTH_ADDRESS address;
+};
+
+// Enumerates the list of known (i.e. already paired) Bluetooth LE devices on
+// this machine. In case of error, returns false and sets |error| with an error
+// message describing the problem.
+// Note: This function returns an error if Bluetooth Low Energy is not supported
+// on this Windows platform.
+bool EnumerateKnownBluetoothLowEnergyDevices(
+ ScopedVector<BluetoothLowEnergyDeviceInfo>* devices,
+ std::string* error);
+
+bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting(
+ const std::string& instance_id,
+ BLUETOOTH_ADDRESS* btha,
+ std::string* error);
+
+} // namespace win
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_WIN_H_
diff --git a/device/bluetooth/bluetooth_low_energy_win_unittest.cc b/device/bluetooth/bluetooth_low_energy_win_unittest.cc
new file mode 100644
index 0000000..2db9d20
--- /dev/null
+++ b/device/bluetooth/bluetooth_low_energy_win_unittest.cc
@@ -0,0 +1,50 @@
+// 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_low_energy_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kValidDeviceInstanceId[] =
+ "BTHLE\\DEV_BC6A29AB5FB0\\8&31038925&0&BC6A29AB5FB0";
+
+const char kInvalidDeviceInstanceId[] =
+ "BTHLE\\BC6A29AB5FB0_DEV_\\8&31038925&0&BC6A29AB5FB0";
+
+} // namespace
+
+namespace device {
+
+class BluetoothLowEnergyWinTest : public testing::Test {};
+
+TEST_F(BluetoothLowEnergyWinTest, ExtractValidBluetoothAddress) {
+ BLUETOOTH_ADDRESS btha;
+ std::string error;
+ bool success =
+ device::win::ExtractBluetoothAddressFromDeviceInstanceIdForTesting(
+ kValidDeviceInstanceId, &btha, &error);
+
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(error.empty());
+ EXPECT_EQ(0xbc, btha.rgBytes[5]);
+ EXPECT_EQ(0x6a, btha.rgBytes[4]);
+ EXPECT_EQ(0x29, btha.rgBytes[3]);
+ EXPECT_EQ(0xab, btha.rgBytes[2]);
+ EXPECT_EQ(0x5f, btha.rgBytes[1]);
+ EXPECT_EQ(0xb0, btha.rgBytes[0]);
+}
+
+TEST_F(BluetoothLowEnergyWinTest, ExtractInvalidBluetoothAddress) {
+ BLUETOOTH_ADDRESS btha;
+ std::string error;
+ bool success =
+ device::win::ExtractBluetoothAddressFromDeviceInstanceIdForTesting(
+ kInvalidDeviceInstanceId, &btha, &error);
+
+ EXPECT_FALSE(success);
+ EXPECT_FALSE(error.empty());
+}
+
+} // namespace device
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
index 7d8da08..a44c59e00 100644
--- a/device/bluetooth/bluetooth_task_manager_win.cc
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -11,7 +11,6 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
@@ -19,6 +18,7 @@
#include "base/threading/sequenced_worker_pool.h"
#include "base/win/scoped_handle.h"
#include "device/bluetooth/bluetooth_init_win.h"
+#include "device/bluetooth/bluetooth_low_energy_win.h"
#include "device/bluetooth/bluetooth_service_record_win.h"
#include "net/base/winsock_init.h"
@@ -32,6 +32,16 @@ const int kMaxDeviceDiscoveryTimeout = 48;
typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
+std::string BluetoothAddressToString(const BLUETOOTH_ADDRESS& btha) {
+ return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
+ btha.rgBytes[5],
+ btha.rgBytes[4],
+ btha.rgBytes[3],
+ btha.rgBytes[2],
+ btha.rgBytes[1],
+ btha.rgBytes[0]);
+}
+
// Populates bluetooth adapter state using adapter_handle.
void GetAdapterState(HANDLE adapter_handle,
device::BluetoothTaskManagerWin::AdapterState* state) {
@@ -43,13 +53,7 @@ void GetAdapterState(HANDLE adapter_handle,
ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
&adapter_info)) {
name = base::SysWideToUTF8(adapter_info.szName);
- address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
- adapter_info.address.rgBytes[5],
- adapter_info.address.rgBytes[4],
- adapter_info.address.rgBytes[3],
- adapter_info.address.rgBytes[2],
- adapter_info.address.rgBytes[1],
- adapter_info.address.rgBytes[0]);
+ address = BluetoothAddressToString(adapter_info.address);
powered = !!BluetoothIsConnectable(adapter_handle);
}
state->name = name;
@@ -60,13 +64,7 @@ void GetAdapterState(HANDLE adapter_handle,
void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
device::BluetoothTaskManagerWin::DeviceState* state) {
state->name = base::SysWideToUTF8(device_info.szName);
- state->address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
- device_info.Address.rgBytes[5],
- device_info.Address.rgBytes[4],
- device_info.Address.rgBytes[3],
- device_info.Address.rgBytes[2],
- device_info.Address.rgBytes[1],
- device_info.Address.rgBytes[0]);
+ state->address = BluetoothAddressToString(device_info.Address);
state->bluetooth_class = device_info.ulClassofDevice;
state->visible = true;
state->connected = !!device_info.fConnected;
@@ -287,6 +285,7 @@ void BluetoothTaskManagerWin::PollAdapter() {
GetKnownDevices();
BluetoothFindRadioClose(handle);
}
+
PostAdapterStateToUi();
}
@@ -390,6 +389,28 @@ void BluetoothTaskManagerWin::DiscoverDevices(int timeout) {
void BluetoothTaskManagerWin::GetKnownDevices() {
ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
SearchDevices(1, true, device_list);
+
+ // Search for Bluetooth Low Energy devices
+ if (win::IsBluetoothLowEnergySupported()) {
+ ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
+ std::string error;
+ bool success =
+ win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
+ if (success) {
+ for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
+ btle_devices.begin();
+ iter != btle_devices.end();
+ ++iter) {
+ win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
+
+ DeviceState* device_state = new DeviceState();
+ device_state->name = device_info->friendly_name;
+ device_state->address = BluetoothAddressToString(device_info->address);
+ device_list->push_back(device_state);
+ }
+ }
+ }
+
if (device_list->empty()) {
delete device_list;
return;