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_device_mac.h"
7 #import <CoreFoundation/CoreFoundation.h>
9 #include "base/mac/mac_util.h"
10 #include "base/mac/scoped_cftyperef.h"
11 #include "base/mac/sdk_forward_declarations.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "device/bluetooth/bluetooth_adapter_mac.h"
15 #include "device/bluetooth/bluetooth_device.h"
17 using device::BluetoothDevice;
18 using device::BluetoothLowEnergyDeviceMac;
22 // Converts a CBUUID to a BluetoothUUID.
23 device::BluetoothUUID BluetoothUUIDWithCBUUID(CBUUID* uuid) {
24 // UUIDString only available OS X >= 10.8.
25 DCHECK(base::mac::IsOSMountainLionOrLater());
26 std::string uuid_c_string = base::SysNSStringToUTF8([uuid UUIDString]);
27 return device::BluetoothUUID(uuid_c_string);
32 BluetoothLowEnergyDeviceMac::BluetoothLowEnergyDeviceMac(
33 BluetoothAdapterMac* adapter,
34 CBPeripheral* peripheral,
35 NSDictionary* advertisement_data,
37 : BluetoothDeviceMac(adapter) {
38 DCHECK(BluetoothAdapterMac::IsLowEnergyAvailable());
39 identifier_ = GetPeripheralIdentifier(peripheral);
40 hash_address_ = GetPeripheralHashAddress(peripheral);
41 Update(peripheral, advertisement_data, rssi);
44 BluetoothLowEnergyDeviceMac::~BluetoothLowEnergyDeviceMac() {
47 void BluetoothLowEnergyDeviceMac::Update(CBPeripheral* peripheral,
48 NSDictionary* advertisement_data,
50 last_update_time_.reset([[NSDate date] retain]);
51 peripheral_.reset([peripheral retain]);
53 NSNumber* connectable =
54 [advertisement_data objectForKey:CBAdvertisementDataIsConnectable];
55 connectable_ = [connectable boolValue];
57 NSDictionary* service_data =
58 [advertisement_data objectForKey:CBAdvertisementDataServiceDataKey];
59 for (CBUUID* uuid in service_data) {
60 NSData* data = [service_data objectForKey:uuid];
61 BluetoothUUID service_uuid = BluetoothUUIDWithCBUUID(uuid);
62 SetServiceData(service_uuid, static_cast<const char*>([data bytes]),
65 NSArray* service_uuids =
66 [advertisement_data objectForKey:CBAdvertisementDataServiceUUIDsKey];
67 for (CBUUID* uuid in service_uuids) {
68 advertised_uuids_.insert(
69 BluetoothUUID(std::string([[uuid UUIDString] UTF8String])));
71 NSArray* overflow_service_uuids = [advertisement_data
72 objectForKey:CBAdvertisementDataOverflowServiceUUIDsKey];
73 for (CBUUID* uuid in overflow_service_uuids) {
74 advertised_uuids_.insert(
75 BluetoothUUID(std::string([[uuid UUIDString] UTF8String])));
79 std::string BluetoothLowEnergyDeviceMac::GetIdentifier() const {
83 uint32 BluetoothLowEnergyDeviceMac::GetBluetoothClass() const {
84 return 0x1F00; // Unspecified Device Class
87 std::string BluetoothLowEnergyDeviceMac::GetAddress() const {
91 BluetoothDevice::VendorIDSource BluetoothLowEnergyDeviceMac::GetVendorIDSource()
93 return VENDOR_ID_UNKNOWN;
96 uint16 BluetoothLowEnergyDeviceMac::GetVendorID() const {
100 uint16 BluetoothLowEnergyDeviceMac::GetProductID() const {
104 uint16 BluetoothLowEnergyDeviceMac::GetDeviceID() const {
108 int BluetoothLowEnergyDeviceMac::GetRSSI() const {
112 bool BluetoothLowEnergyDeviceMac::IsPaired() const {
116 bool BluetoothLowEnergyDeviceMac::IsConnected() const {
117 return IsGattConnected();
120 bool BluetoothLowEnergyDeviceMac::IsGattConnected() const {
121 return (GetPeripheralState() == CBPeripheralStateConnected);
124 bool BluetoothLowEnergyDeviceMac::IsConnectable() const {
128 bool BluetoothLowEnergyDeviceMac::IsConnecting() const {
132 BluetoothDevice::UUIDList BluetoothLowEnergyDeviceMac::GetUUIDs() const {
133 return BluetoothDevice::UUIDList(advertised_uuids_.begin(),
134 advertised_uuids_.end());
137 int16 BluetoothLowEnergyDeviceMac::GetInquiryRSSI() const {
138 return kUnknownPower;
141 int16 BluetoothLowEnergyDeviceMac::GetInquiryTxPower() const {
143 return kUnknownPower;
146 bool BluetoothLowEnergyDeviceMac::ExpectingPinCode() const {
150 bool BluetoothLowEnergyDeviceMac::ExpectingPasskey() const {
154 bool BluetoothLowEnergyDeviceMac::ExpectingConfirmation() const {
158 void BluetoothLowEnergyDeviceMac::GetConnectionInfo(
159 const ConnectionInfoCallback& callback) {
163 void BluetoothLowEnergyDeviceMac::Connect(
164 PairingDelegate* pairing_delegate,
165 const base::Closure& callback,
166 const ConnectErrorCallback& error_callback) {
170 void BluetoothLowEnergyDeviceMac::SetPinCode(const std::string& pincode) {
174 void BluetoothLowEnergyDeviceMac::SetPasskey(uint32 passkey) {
178 void BluetoothLowEnergyDeviceMac::ConfirmPairing() {
182 void BluetoothLowEnergyDeviceMac::RejectPairing() {
186 void BluetoothLowEnergyDeviceMac::CancelPairing() {
190 void BluetoothLowEnergyDeviceMac::Disconnect(
191 const base::Closure& callback,
192 const ErrorCallback& error_callback) {
196 void BluetoothLowEnergyDeviceMac::Forget(const ErrorCallback& error_callback) {
200 void BluetoothLowEnergyDeviceMac::ConnectToService(
201 const BluetoothUUID& uuid,
202 const ConnectToServiceCallback& callback,
203 const ConnectToServiceErrorCallback& error_callback) {
207 void BluetoothLowEnergyDeviceMac::ConnectToServiceInsecurely(
208 const device::BluetoothUUID& uuid,
209 const ConnectToServiceCallback& callback,
210 const ConnectToServiceErrorCallback& error_callback) {
214 void BluetoothLowEnergyDeviceMac::CreateGattConnection(
215 const GattConnectionCallback& callback,
216 const ConnectErrorCallback& error_callback) {
220 NSDate* BluetoothLowEnergyDeviceMac::GetLastUpdateTime() const {
221 return last_update_time_.get();
224 std::string BluetoothLowEnergyDeviceMac::GetDeviceName() const {
225 return base::SysNSStringToUTF8([peripheral_ name]);
228 void BluetoothLowEnergyDeviceMac::CreateGattConnectionImpl() {
229 // Mac implementation does not yet use the default CreateGattConnection
230 // implementation. http://crbug.com/520774
234 void BluetoothLowEnergyDeviceMac::DisconnectGatt() {
235 // Mac implementation does not yet use the default CreateGattConnection
236 // implementation. http://crbug.com/520774
241 std::string BluetoothLowEnergyDeviceMac::GetPeripheralIdentifier(
242 CBPeripheral* peripheral) {
243 DCHECK(BluetoothAdapterMac::IsLowEnergyAvailable());
244 NSUUID* uuid = [peripheral identifier];
245 NSString* uuidString = [uuid UUIDString];
246 return base::SysNSStringToUTF8(uuidString);
250 std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress(
251 CBPeripheral* peripheral) {
252 const size_t kCanonicalAddressNumberOfBytes = 6;
253 char raw[kCanonicalAddressNumberOfBytes];
254 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw,
256 std::string hash = base::HexEncode(raw, sizeof(raw));
257 return BluetoothDevice::CanonicalizeAddress(hash);
260 CBPeripheralState BluetoothLowEnergyDeviceMac::GetPeripheralState() const {
261 Class peripheral_class = NSClassFromString(@"CBPeripheral");
262 base::scoped_nsobject<NSMethodSignature> signature([[peripheral_class
263 instanceMethodSignatureForSelector:@selector(state)] retain]);
264 base::scoped_nsobject<NSInvocation> invocation(
265 [[NSInvocation invocationWithMethodSignature:signature] retain]);
266 [invocation setTarget:peripheral_];
267 [invocation setSelector:@selector(state)];
269 CBPeripheralState state = CBPeripheralStateDisconnected;
270 [invocation getReturnValue:&state];