1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_low_energy_discovery_manager_mac.h"
7 #include "base/mac/mac_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "device/bluetooth/bluetooth_low_energy_device_mac.h"
12 using device::BluetoothLowEnergyDeviceMac;
13 using device::BluetoothLowEnergyDiscoveryManagerMac;
14 using device::BluetoothLowEnergyDiscoveryManagerMacDelegate;
18 // This class is a helper to call some protected methods in
19 // BluetoothLowEnergyDiscoveryManagerMac.
20 class BluetoothLowEnergyDiscoveryManagerMacDelegate {
22 BluetoothLowEnergyDiscoveryManagerMacDelegate(
23 BluetoothLowEnergyDiscoveryManagerMac* manager)
24 : manager_(manager) {}
26 virtual ~BluetoothLowEnergyDiscoveryManagerMacDelegate() {}
28 virtual void DiscoveredPeripheral(CBPeripheral* peripheral,
29 NSDictionary* advertisementData,
31 manager_->DiscoveredPeripheral(peripheral, advertisementData, rssi);
34 virtual void TryStartDiscovery() { manager_->TryStartDiscovery(); }
37 BluetoothLowEnergyDiscoveryManagerMac* manager_;
42 // This class will serve as the Objective-C delegate of CBCentralManager.
43 @interface BluetoothLowEnergyDiscoveryManagerMacBridge
44 : NSObject<CBCentralManagerDelegate> {
45 BluetoothLowEnergyDiscoveryManagerMac* manager_;
46 scoped_ptr<BluetoothLowEnergyDiscoveryManagerMacDelegate> delegate_;
49 - (id)initWithManager:(BluetoothLowEnergyDiscoveryManagerMac*)manager;
53 @implementation BluetoothLowEnergyDiscoveryManagerMacBridge
55 - (id)initWithManager:(BluetoothLowEnergyDiscoveryManagerMac*)manager {
56 if ((self = [super init])) {
59 new BluetoothLowEnergyDiscoveryManagerMacDelegate(manager_));
64 - (void)centralManager:(CBCentralManager*)central
65 didDiscoverPeripheral:(CBPeripheral*)peripheral
66 advertisementData:(NSDictionary*)advertisementData
67 RSSI:(NSNumber*)RSSI {
68 // Notifies the discovery of a device.
69 delegate_->DiscoveredPeripheral(peripheral, advertisementData,
73 - (void)centralManagerDidUpdateState:(CBCentralManager*)central {
74 // Notifies when the powered state of the central manager changed.
75 delegate_->TryStartDiscovery();
80 BluetoothLowEnergyDiscoveryManagerMac::
81 ~BluetoothLowEnergyDiscoveryManagerMac() {
85 bool BluetoothLowEnergyDiscoveryManagerMac::IsDiscovering() const {
89 void BluetoothLowEnergyDiscoveryManagerMac::StartDiscovery(
90 BluetoothDevice::UUIDList services_uuids) {
94 services_uuids_ = services_uuids;
98 void BluetoothLowEnergyDiscoveryManagerMac::TryStartDiscovery() {
107 // Can only start if the bluetooth power is turned on.
108 if ([manager_ state] != CBCentralManagerStatePoweredOn) {
112 // Converts the services UUIDs to a CoreBluetooth data structure.
113 NSMutableArray* services = nil;
114 if (!services_uuids_.empty()) {
115 services = [NSMutableArray array];
116 for (auto& service_uuid : services_uuids_) {
117 NSString* uuidString =
118 base::SysUTF8ToNSString(service_uuid.canonical_value().c_str());
119 Class aClass = NSClassFromString(@"CBUUID");
120 CBUUID* uuid = [aClass UUIDWithString:uuidString];
121 [services addObject:uuid];
125 [manager_ scanForPeripheralsWithServices:services options:nil];
129 void BluetoothLowEnergyDiscoveryManagerMac::StopDiscovery() {
130 if (discovering_ && !pending_) {
133 discovering_ = false;
136 void BluetoothLowEnergyDiscoveryManagerMac::DiscoveredPeripheral(
137 CBPeripheral* peripheral,
138 NSDictionary* advertisementData,
140 // Look for existing device.
141 auto iter = devices_.find(
142 BluetoothLowEnergyDeviceMac::GetPeripheralIdentifier(peripheral));
143 if (iter == devices_.end()) {
144 // A device has been added.
145 BluetoothLowEnergyDeviceMac* device =
146 new BluetoothLowEnergyDeviceMac(peripheral, advertisementData, rssi);
147 devices_.insert(devices_.begin(),
148 std::make_pair(device->GetIdentifier(), device));
149 observer_->DeviceFound(device);
153 // A device has an update.
154 BluetoothLowEnergyDeviceMac* old_device = iter->second;
155 old_device->Update(peripheral, advertisementData, rssi);
156 observer_->DeviceUpdated(old_device);
159 BluetoothLowEnergyDiscoveryManagerMac*
160 BluetoothLowEnergyDiscoveryManagerMac::Create(Observer* observer) {
161 return new BluetoothLowEnergyDiscoveryManagerMac(observer);
164 BluetoothLowEnergyDiscoveryManagerMac::BluetoothLowEnergyDiscoveryManagerMac(
166 : observer_(observer) {
167 bridge_.reset([[BluetoothLowEnergyDiscoveryManagerMacBridge alloc]
168 initWithManager:this]);
169 // Since CoreBluetooth is only available on OS X 10.7 or later, we
170 // instantiate CBCentralManager only for OS X >= 10.7.
171 if (base::mac::IsOSLionOrLater()) {
172 Class aClass = NSClassFromString(@"CBCentralManager");
174 [[aClass alloc] initWithDelegate:bridge_
175 queue:dispatch_get_main_queue()]);
177 discovering_ = false;
180 void BluetoothLowEnergyDiscoveryManagerMac::ClearDevices() {
181 STLDeleteValues(&devices_);