blob: 11d40caa6261d6a8db61b30986e5b5ab3fcfbe9e [file] [log] [blame]
// Copyright 2015 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_discovery_manager_mac.h"
#include "base/mac/mac_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/sys_string_conversions.h"
#include "device/bluetooth/bluetooth_low_energy_device_mac.h"
using device::BluetoothLowEnergyDeviceMac;
using device::BluetoothLowEnergyDiscoveryManagerMac;
using device::BluetoothLowEnergyDiscoveryManagerMacDelegate;
namespace device {
// This class is a helper to call some protected methods in
// BluetoothLowEnergyDiscoveryManagerMac.
class BluetoothLowEnergyDiscoveryManagerMacDelegate {
public:
BluetoothLowEnergyDiscoveryManagerMacDelegate(
BluetoothLowEnergyDiscoveryManagerMac* manager)
: manager_(manager) {}
virtual ~BluetoothLowEnergyDiscoveryManagerMacDelegate() {}
virtual void DiscoveredPeripheral(CBPeripheral* peripheral,
NSDictionary* advertisementData,
int rssi) {
manager_->DiscoveredPeripheral(peripheral, advertisementData, rssi);
}
virtual void TryStartDiscovery() { manager_->TryStartDiscovery(); }
private:
BluetoothLowEnergyDiscoveryManagerMac* manager_;
};
} // namespace device
// This class will serve as the Objective-C delegate of CBCentralManager.
@interface BluetoothLowEnergyDiscoveryManagerMacBridge
: NSObject<CBCentralManagerDelegate> {
BluetoothLowEnergyDiscoveryManagerMac* manager_;
scoped_ptr<BluetoothLowEnergyDiscoveryManagerMacDelegate> delegate_;
}
- (id)initWithManager:(BluetoothLowEnergyDiscoveryManagerMac*)manager;
@end
@implementation BluetoothLowEnergyDiscoveryManagerMacBridge
- (id)initWithManager:(BluetoothLowEnergyDiscoveryManagerMac*)manager {
if ((self = [super init])) {
manager_ = manager;
delegate_.reset(
new BluetoothLowEnergyDiscoveryManagerMacDelegate(manager_));
}
return self;
}
- (void)centralManager:(CBCentralManager*)central
didDiscoverPeripheral:(CBPeripheral*)peripheral
advertisementData:(NSDictionary*)advertisementData
RSSI:(NSNumber*)RSSI {
// Notifies the discovery of a device.
delegate_->DiscoveredPeripheral(peripheral, advertisementData,
[RSSI intValue]);
}
- (void)centralManagerDidUpdateState:(CBCentralManager*)central {
// Notifies when the powered state of the central manager changed.
delegate_->TryStartDiscovery();
}
@end
BluetoothLowEnergyDiscoveryManagerMac::
~BluetoothLowEnergyDiscoveryManagerMac() {
ClearDevices();
}
bool BluetoothLowEnergyDiscoveryManagerMac::IsDiscovering() const {
return discovering_;
}
void BluetoothLowEnergyDiscoveryManagerMac::StartDiscovery(
BluetoothDevice::UUIDList services_uuids) {
ClearDevices();
discovering_ = true;
pending_ = true;
services_uuids_ = services_uuids;
TryStartDiscovery();
}
void BluetoothLowEnergyDiscoveryManagerMac::TryStartDiscovery() {
if (!discovering_) {
return;
}
if (!pending_) {
return;
}
// Can only start if the bluetooth power is turned on.
if ([manager_ state] != CBCentralManagerStatePoweredOn) {
return;
}
// Converts the services UUIDs to a CoreBluetooth data structure.
NSMutableArray* services = nil;
if (!services_uuids_.empty()) {
services = [NSMutableArray array];
for (auto& service_uuid : services_uuids_) {
NSString* uuidString =
base::SysUTF8ToNSString(service_uuid.canonical_value().c_str());
Class aClass = NSClassFromString(@"CBUUID");
CBUUID* uuid = [aClass UUIDWithString:uuidString];
[services addObject:uuid];
}
};
[manager_ scanForPeripheralsWithServices:services options:nil];
pending_ = false;
}
void BluetoothLowEnergyDiscoveryManagerMac::StopDiscovery() {
if (discovering_ && !pending_) {
[manager_ stopScan];
}
discovering_ = false;
}
void BluetoothLowEnergyDiscoveryManagerMac::DiscoveredPeripheral(
CBPeripheral* peripheral,
NSDictionary* advertisementData,
int rssi) {
// Look for existing device.
auto iter = devices_.find(
BluetoothLowEnergyDeviceMac::GetPeripheralIdentifier(peripheral));
if (iter == devices_.end()) {
// A device has been added.
BluetoothLowEnergyDeviceMac* device =
new BluetoothLowEnergyDeviceMac(peripheral, advertisementData, rssi);
devices_.insert(devices_.begin(),
std::make_pair(device->GetIdentifier(), device));
observer_->DeviceFound(device);
return;
}
// A device has an update.
BluetoothLowEnergyDeviceMac* old_device = iter->second;
old_device->Update(peripheral, advertisementData, rssi);
observer_->DeviceUpdated(old_device);
}
BluetoothLowEnergyDiscoveryManagerMac*
BluetoothLowEnergyDiscoveryManagerMac::Create(Observer* observer) {
return new BluetoothLowEnergyDiscoveryManagerMac(observer);
}
BluetoothLowEnergyDiscoveryManagerMac::BluetoothLowEnergyDiscoveryManagerMac(
Observer* observer)
: observer_(observer) {
bridge_.reset([[BluetoothLowEnergyDiscoveryManagerMacBridge alloc]
initWithManager:this]);
// Since CoreBluetooth is only available on OS X 10.7 or later, we
// instantiate CBCentralManager only for OS X >= 10.7.
if (base::mac::IsOSLionOrLater()) {
Class aClass = NSClassFromString(@"CBCentralManager");
manager_.reset(
[[aClass alloc] initWithDelegate:bridge_
queue:dispatch_get_main_queue()]);
}
discovering_ = false;
}
void BluetoothLowEnergyDiscoveryManagerMac::ClearDevices() {
STLDeleteValues(&devices_);
}