12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_task_manager_win.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <winsock2.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/ref_counted.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/sequenced_task_runner.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_handle.h"
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "device/bluetooth/bluetooth_device.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_init_win.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "device/bluetooth/bluetooth_low_energy_win.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_service_record_win.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/winsock_init.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kNumThreadsInWorkerPool = 3;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaxNumDeviceAddressChar = 127;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kServiceDiscoveryResultBufferSize = 5000;
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// out for the inquiry, expressed in increments of 1.28 seconds. For example, an
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// value for this member is 48. When a value greater than 48 is used, the
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// calling function immediately fails and returns
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kMaxDeviceDiscoveryTimeoutMultiplier = 48;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtypedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Note: The string returned here must have the same format as
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// BluetoothDevice::CanonicalizeAddress.
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) {
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                          btha.rgBytes[5],
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                          btha.rgBytes[4],
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                          btha.rgBytes[3],
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                          btha.rgBytes[2],
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                          btha.rgBytes[1],
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                          btha.rgBytes[0]);
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result));
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return result;
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid(
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const BTH_LE_UUID& bth_le_uuid) {
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (bth_le_uuid.IsShortUuid) {
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::string uuid_hex =
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid);
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return device::BluetoothUUID(uuid_hex);
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return device::BluetoothUUID(
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data1,
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data2,
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data3,
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[0],
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[1],
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[2],
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[3],
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[4],
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[5],
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[6],
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           bth_le_uuid.Value.LongUuid.Data4[7]));
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Populates bluetooth adapter state using adapter_handle.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GetAdapterState(HANDLE adapter_handle,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     device::BluetoothTaskManagerWin::AdapterState* state) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string name;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string address;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool powered = false;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (adapter_handle &&
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             &adapter_info)) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    name = base::SysWideToUTF8(adapter_info.szName);
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    address = BluetoothAddressToCanonicalString(adapter_info.address);
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    powered = !!BluetoothIsConnectable(adapter_handle);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->name = name;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->address = address;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->powered = powered;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    device::BluetoothTaskManagerWin::DeviceState* state) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->name = base::SysWideToUTF8(device_info.szName);
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  state->address = BluetoothAddressToCanonicalString(device_info.Address);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->bluetooth_class = device_info.ulClassofDevice;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->visible = true;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->connected = !!device_info.fConnected;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state->authenticated = !!device_info.fAuthenticated;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace device {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) {
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::AdapterState::~AdapterState() {
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() {
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() {
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::DeviceState::DeviceState()
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : bluetooth_class(0),
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      visible(false),
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      connected(false),
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      authenticated(false) {
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::DeviceState::~DeviceState() {
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BluetoothTaskManagerWin::BluetoothTaskManagerWin(
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : ui_task_runner_(ui_task_runner),
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      discovering_(false),
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      current_logging_batch_count_(0) {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(observer);
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.AddObserver(observer);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(observer);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.RemoveObserver(observer);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::Initialize() {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               kBluetoothThreadName);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InitializeWithBluetoothTaskRunner(
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          worker_pool_->GetSequenceToken(),
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bluetooth_task_runner_ = bluetooth_task_runner;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bluetooth_task_runner_->PostTask(
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::StartPolling() {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (device::bluetooth_init_win::HasBluetoothStack()) {
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PollAdapter();
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // IF the bluetooth stack is not available, we still send an empty state
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to BluetoothAdapter so that it is marked initialized, but the adapter
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // will not be present.
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AdapterState* state = new AdapterState();
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Owned(state)));
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::Shutdown() {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (worker_pool_)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    worker_pool_->Shutdown();
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool powered,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& callback,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BluetoothAdapter::ErrorCallback& error_callback) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bluetooth_task_runner_->PostTask(
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::SetPowered,
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 powered,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback,
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 error_callback));
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bluetooth_task_runner_->PostTask(
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bluetooth_task_runner_->PostTask(
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::LogPollingError(const char* message,
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                              int win32_error) {
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int kLogPeriodInMilliseconds = 60 * 1000;
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int kMaxMessagesPerLogPeriod = 10;
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Check if we need to discard this message
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!current_logging_batch_ticks_.is_null()) {
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (base::TimeTicks::Now() - current_logging_batch_ticks_ <=
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) {
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod)
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // The batch expired, reset it to "null".
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      current_logging_batch_ticks_ = base::TimeTicks();
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Keep track of this batch of messages
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (current_logging_batch_ticks_.is_null()) {
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    current_logging_batch_ticks_ = base::TimeTicks::Now();
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    current_logging_batch_count_ = 0;
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ++current_logging_batch_count_;
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Log the message
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (win32_error == 0)
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(WARNING) << message;
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  else
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(WARNING) << message << ": "
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 << logging::SystemErrorCodeToString(win32_error);
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    AdapterStateChanged(*state));
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    DiscoveryStarted(success));
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::OnDiscoveryStopped() {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    DiscoveryStopped());
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::OnDevicesPolled(
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ScopedVector<DeviceState>* devices) {
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices));
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PollAdapter() {
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Skips updating the adapter info if the adapter is in discovery mode.
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!discovering_) {
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (adapter_handle_)
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      adapter_handle_.Close();
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    HANDLE temp_adapter_handle;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        &adapter_param, &temp_adapter_handle);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (handle) {
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      adapter_handle_.Set(temp_adapter_handle);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetKnownDevices();
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BluetoothFindRadioClose(handle);
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PostAdapterStateToUi();
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Re-poll.
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bluetooth_task_runner_->PostDelayedTask(
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::PollAdapter,
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this),
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta::FromMilliseconds(kPollIntervalMs));
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostAdapterStateToUi() {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AdapterState* state = new AdapterState();
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetAdapterState(adapter_handle_, state);
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_task_runner_->PostTask(
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Owned(state)));
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::SetPowered(
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool powered,
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& callback,
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BluetoothAdapter::ErrorCallback& error_callback) {
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = false;
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (adapter_handle_) {
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!powered)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BluetoothEnableDiscovery(adapter_handle_, false);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (success) {
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PostAdapterStateToUi();
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(FROM_HERE, callback);
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(FROM_HERE, error_callback);
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::StartDiscovery() {
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_task_runner_->PostTask(
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 !!adapter_handle_));
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!adapter_handle_)
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  discovering_ = true;
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DiscoverDevices(1);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::StopDiscovery() {
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  discovering_ = false;
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_task_runner_->PostTask(
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!discovering_ || !adapter_handle_) {
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<ScopedVector<DeviceState> > device_list(
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new ScopedVector<DeviceState>());
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (SearchDevices(timeout_multiplier, false, device_list.get())) {
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   base::Owned(device_list.release())));
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ++timeout_multiplier;
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bluetooth_task_runner_->PostTask(
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::GetKnownDevices() {
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<ScopedVector<DeviceState> > device_list(
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new ScopedVector<DeviceState>());
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (SearchDevices(1, true, device_list.get())) {
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   this,
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   base::Owned(device_list.release())));
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::SearchDevices(
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int timeout_multiplier,
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool search_cached_devices_only,
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ScopedVector<DeviceState>* device_list) {
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return SearchClassicDevices(
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)             timeout_multiplier, search_cached_devices_only, device_list) &&
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         SearchLowEnergyDevices(device_list) &&
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         DiscoverServices(device_list, search_cached_devices_only);
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::SearchClassicDevices(
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int timeout_multiplier,
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool search_cached_devices_only,
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ScopedVector<DeviceState>* device_list) {
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds.
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params;
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ZeroMemory(&device_search_params, sizeof(device_search_params));
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.fReturnAuthenticated = 1;
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.fReturnRemembered = 1;
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1);
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.fReturnConnected = 1;
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1);
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_search_params.cTimeoutMultiplier = timeout_multiplier;
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  BLUETOOTH_DEVICE_INFO device_info;
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ZeroMemory(&device_info, sizeof(device_info));
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HBLUETOOTH_DEVICE_FIND handle =
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BluetoothFindFirstDevice(&device_search_params, &device_info);
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!handle) {
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int last_error = GetLastError();
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (last_error == ERROR_NO_MORE_ITEMS) {
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return true;  // No devices is not an error.
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LogPollingError("Error calling BluetoothFindFirstDevice", last_error);
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (true) {
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DeviceState* device_state = new DeviceState();
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    GetDeviceState(device_info, device_state);
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_list->push_back(device_state);
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Reset device info before next call (as a safety precaution).
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ZeroMemory(&device_info, sizeof(device_info));
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!BluetoothFindNextDevice(handle, &device_info)) {
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int last_error = GetLastError();
4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (last_error == ERROR_NO_MORE_ITEMS) {
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;  // No more items is expected error when done enumerating.
460116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
4615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LogPollingError("Error calling BluetoothFindNextDevice", last_error);
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BluetoothFindDeviceClose(handle);
4635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
464116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
465116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
466116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!BluetoothFindDeviceClose(handle)) {
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError());
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScopedVector<DeviceState>* device_list) {
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!win::IsBluetoothLowEnergySupported())
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return true;  // Bluetooth LE not supported is not an error.
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string error;
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool success =
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!success) {
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LogPollingError(error.c_str(), 0);
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           btle_devices.begin();
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       iter != btle_devices.end();
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       ++iter) {
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DeviceState* device_state = new DeviceState();
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_state->name = device_info->friendly_name;
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_state->address =
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        BluetoothAddressToCanonicalString(device_info->address);
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_state->visible = device_info->visible;
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_state->authenticated = device_info->authenticated;
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_state->connected = device_info->connected;
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_state->path = device_info->path;
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_list->push_back(device_state);
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::DiscoverServices(
5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ScopedVector<DeviceState>* device_list,
5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool search_cached_services_only) {
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::EnsureWinsockInit();
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      iter != device_list->end();
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++iter) {
5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DeviceState* device = (*iter);
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScopedVector<ServiceRecordState>* service_record_states =
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &(*iter)->service_record_states;
517c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if ((*iter)->is_bluetooth_classic()) {
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!DiscoverClassicDeviceServices(device->address,
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         L2CAP_PROTOCOL_UUID,
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         search_cached_services_only,
5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         service_record_states)) {
5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return false;
5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!DiscoverLowEnergyDeviceServices(device->path,
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           service_record_states)) {
5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return false;
5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& device_address,
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const GUID& protocol_uuid,
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool search_cached_services_only,
5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ScopedVector<ServiceRecordState>* service_record_states) {
54003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int error_code =
54103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      DiscoverClassicDeviceServicesWorker(device_address,
54203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                          protocol_uuid,
54303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                          search_cached_services_only,
54403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                          service_record_states);
54503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // If the device is "offline", no services are returned when specifying
54603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // "LUP_FLUSHCACHE". Try again without flushing the cache so that the list
54703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // of previously known services is returned.
54803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!search_cached_services_only &&
54903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      (error_code == WSASERVICE_NOT_FOUND || error_code == WSANO_DATA)) {
55003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    error_code = DiscoverClassicDeviceServicesWorker(
55103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        device_address, protocol_uuid, true, service_record_states);
55203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
55303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
55403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return (error_code == ERROR_SUCCESS);
55503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
55603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
55703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker(
55803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& device_address,
55903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const GUID& protocol_uuid,
56003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool search_cached_services_only,
56103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ScopedVector<ServiceRecordState>* service_record_states) {
5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  WSAQUERYSET sdp_query;
5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ZeroMemory(&sdp_query, sizeof(sdp_query));
5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  sdp_query.dwSize = sizeof(sdp_query);
5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GUID protocol = protocol_uuid;
5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  sdp_query.lpServiceClassId = &protocol;
5685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  sdp_query.dwNameSpace = NS_BTH;
5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  wchar_t device_address_context[kMaxNumDeviceAddressChar];
5705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
5715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_address_context, kMaxNumDeviceAddressChar);
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_address_context[length] = NULL;
5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  sdp_query.lpszContext = device_address_context;
5745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DWORD control_flags = LUP_RETURN_ALL;
5755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // See http://goo.gl/t1Hulo: "Applications should generally specify
5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached
5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // information and establish an over-the-air SDP connection to the specified
5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // device to perform the SDP search. This non-cached operation may take
5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // several seconds (whereas a cached search returns quickly)."
5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // of services for devices which have not been discovered before.
5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!search_cached_services_only)
5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    control_flags |= LUP_FLUSHCACHE;
5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HANDLE sdp_handle;
5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (ERROR_SUCCESS !=
5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) {
58703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    int last_error = WSAGetLastError();
58803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If the device is "offline", no services are returned when specifying
58903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // "LUP_FLUSHCACHE". Don't log error in that case.
59003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!search_cached_services_only &&
59103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        (last_error == WSASERVICE_NOT_FOUND || last_error == WSANO_DATA)) {
59203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return last_error;
59303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
59403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LogPollingError("Error calling WSALookupServiceBegin", last_error);
59503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return last_error;
5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  char sdp_buffer[kServiceDiscoveryResultBufferSize];
5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
5995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (true) {
6005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DWORD sdp_buffer_size = sizeof(sdp_buffer);
6015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (ERROR_SUCCESS !=
6025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        WSALookupServiceNext(
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) {
6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int last_error = WSAGetLastError();
6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) {
6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
6085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LogPollingError("Error calling WSALookupServiceNext", last_error);
6095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      WSALookupServiceEnd(sdp_handle);
61003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return last_error;
6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ServiceRecordState* service_record_state = new ServiceRecordState();
6135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    service_record_state->name =
6145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
6155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      service_record_state->sdp_bytes.push_back(
6175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          sdp_result_data->lpBlob->pBlobData[i]);
6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
6195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    service_record_states->push_back(service_record_state);
6205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
62203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    int last_error = WSAGetLastError();
62303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LogPollingError("Error calling WSALookupServiceEnd", last_error);
62403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return last_error;
6255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
62703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return ERROR_SUCCESS;
6285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
6315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::FilePath& device_path,
6325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ScopedVector<ServiceRecordState>* service_record_states) {
6335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!win::IsBluetoothLowEnergySupported())
6345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return true;  // Bluetooth LE not supported is not an error.
6355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string error;
6375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
6385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool success = win::EnumerateKnownBluetoothLowEnergyServices(
6395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_path, &services, &error);
6405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!success) {
6415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LogPollingError(error.c_str(), 0);
6425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
6435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 =
6465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           services.begin();
6475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       iter2 != services.end();
6485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       ++iter2) {
6495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ServiceRecordState* service_state = new ServiceRecordState();
6505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    service_state->gatt_uuid =
6515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid);
6525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    service_record_states->push_back(service_state);
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace device
658