// 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_device_mac.h" #import #include #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/sdk_forward_declarations.h" #include "base/strings/string_number_conversions.h" #include "base/strings/sys_string_conversions.h" #include "device/bluetooth/bluetooth_adapter_mac.h" #include "device/bluetooth/bluetooth_device.h" using device::BluetoothDevice; using device::BluetoothLowEnergyDeviceMac; namespace { // Converts a CBUUID to a BluetoothUUID. device::BluetoothUUID BluetoothUUIDWithCBUUID(CBUUID* uuid) { // UUIDString only available OS X >= 10.8. DCHECK(base::mac::IsOSMountainLionOrLater()); std::string uuid_c_string = base::SysNSStringToUTF8([uuid UUIDString]); return device::BluetoothUUID(uuid_c_string); } } // namespace BluetoothLowEnergyDeviceMac::BluetoothLowEnergyDeviceMac( BluetoothAdapterMac* adapter, CBPeripheral* peripheral, NSDictionary* advertisement_data, int rssi) : BluetoothDeviceMac(adapter) { DCHECK(BluetoothAdapterMac::IsLowEnergyAvailable()); identifier_ = GetPeripheralIdentifier(peripheral); hash_address_ = GetPeripheralHashAddress(peripheral); Update(peripheral, advertisement_data, rssi); } BluetoothLowEnergyDeviceMac::~BluetoothLowEnergyDeviceMac() { } void BluetoothLowEnergyDeviceMac::Update(CBPeripheral* peripheral, NSDictionary* advertisement_data, int rssi) { last_update_time_.reset([[NSDate date] retain]); peripheral_.reset([peripheral retain]); rssi_ = rssi; NSNumber* connectable = [advertisement_data objectForKey:CBAdvertisementDataIsConnectable]; connectable_ = [connectable boolValue]; ClearServiceData(); NSDictionary* service_data = [advertisement_data objectForKey:CBAdvertisementDataServiceDataKey]; for (CBUUID* uuid in service_data) { NSData* data = [service_data objectForKey:uuid]; BluetoothUUID service_uuid = BluetoothUUIDWithCBUUID(uuid); SetServiceData(service_uuid, static_cast([data bytes]), [data length]); } NSArray* service_uuids = [advertisement_data objectForKey:CBAdvertisementDataServiceUUIDsKey]; for (CBUUID* uuid in service_uuids) { advertised_uuids_.insert( BluetoothUUID(std::string([[uuid UUIDString] UTF8String]))); } NSArray* overflow_service_uuids = [advertisement_data objectForKey:CBAdvertisementDataOverflowServiceUUIDsKey]; for (CBUUID* uuid in overflow_service_uuids) { advertised_uuids_.insert( BluetoothUUID(std::string([[uuid UUIDString] UTF8String]))); } } std::string BluetoothLowEnergyDeviceMac::GetIdentifier() const { return identifier_; } uint32_t BluetoothLowEnergyDeviceMac::GetBluetoothClass() const { return 0x1F00; // Unspecified Device Class } std::string BluetoothLowEnergyDeviceMac::GetAddress() const { return hash_address_; } BluetoothDevice::VendorIDSource BluetoothLowEnergyDeviceMac::GetVendorIDSource() const { return VENDOR_ID_UNKNOWN; } uint16_t BluetoothLowEnergyDeviceMac::GetVendorID() const { return 0; } uint16_t BluetoothLowEnergyDeviceMac::GetProductID() const { return 0; } uint16_t BluetoothLowEnergyDeviceMac::GetDeviceID() const { return 0; } int BluetoothLowEnergyDeviceMac::GetRSSI() const { return rssi_; } bool BluetoothLowEnergyDeviceMac::IsPaired() const { return false; } bool BluetoothLowEnergyDeviceMac::IsConnected() const { return IsGattConnected(); } bool BluetoothLowEnergyDeviceMac::IsGattConnected() const { return (GetPeripheralState() == CBPeripheralStateConnected); } bool BluetoothLowEnergyDeviceMac::IsConnectable() const { return connectable_; } bool BluetoothLowEnergyDeviceMac::IsConnecting() const { return false; } BluetoothDevice::UUIDList BluetoothLowEnergyDeviceMac::GetUUIDs() const { return BluetoothDevice::UUIDList(advertised_uuids_.begin(), advertised_uuids_.end()); } int16_t BluetoothLowEnergyDeviceMac::GetInquiryRSSI() const { return kUnknownPower; } int16_t BluetoothLowEnergyDeviceMac::GetInquiryTxPower() const { NOTIMPLEMENTED(); return kUnknownPower; } bool BluetoothLowEnergyDeviceMac::ExpectingPinCode() const { return false; } bool BluetoothLowEnergyDeviceMac::ExpectingPasskey() const { return false; } bool BluetoothLowEnergyDeviceMac::ExpectingConfirmation() const { return false; } void BluetoothLowEnergyDeviceMac::GetConnectionInfo( const ConnectionInfoCallback& callback) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::Connect( PairingDelegate* pairing_delegate, const base::Closure& callback, const ConnectErrorCallback& error_callback) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::SetPinCode(const std::string& pincode) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::SetPasskey(uint32_t passkey) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::ConfirmPairing() { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::RejectPairing() { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::CancelPairing() { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::Disconnect( const base::Closure& callback, const ErrorCallback& error_callback) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::Forget(const base::Closure& callback, const ErrorCallback& error_callback) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::ConnectToService( const BluetoothUUID& uuid, const ConnectToServiceCallback& callback, const ConnectToServiceErrorCallback& error_callback) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::ConnectToServiceInsecurely( const device::BluetoothUUID& uuid, const ConnectToServiceCallback& callback, const ConnectToServiceErrorCallback& error_callback) { NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::CreateGattConnection( const GattConnectionCallback& callback, const ConnectErrorCallback& error_callback) { NOTIMPLEMENTED(); } NSDate* BluetoothLowEnergyDeviceMac::GetLastUpdateTime() const { return last_update_time_.get(); } std::string BluetoothLowEnergyDeviceMac::GetDeviceName() const { return base::SysNSStringToUTF8([peripheral_ name]); } void BluetoothLowEnergyDeviceMac::CreateGattConnectionImpl() { // Mac implementation does not yet use the default CreateGattConnection // implementation. http://crbug.com/520774 NOTIMPLEMENTED(); } void BluetoothLowEnergyDeviceMac::DisconnectGatt() { // Mac implementation does not yet use the default CreateGattConnection // implementation. http://crbug.com/520774 NOTIMPLEMENTED(); } // static std::string BluetoothLowEnergyDeviceMac::GetPeripheralIdentifier( CBPeripheral* peripheral) { DCHECK(BluetoothAdapterMac::IsLowEnergyAvailable()); NSUUID* uuid = [peripheral identifier]; NSString* uuidString = [uuid UUIDString]; return base::SysNSStringToUTF8(uuidString); } // static std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress( CBPeripheral* peripheral) { const size_t kCanonicalAddressNumberOfBytes = 6; char raw[kCanonicalAddressNumberOfBytes]; crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, sizeof(raw)); std::string hash = base::HexEncode(raw, sizeof(raw)); return BluetoothDevice::CanonicalizeAddress(hash); } CBPeripheralState BluetoothLowEnergyDeviceMac::GetPeripheralState() const { Class peripheral_class = NSClassFromString(@"CBPeripheral"); base::scoped_nsobject signature([[peripheral_class instanceMethodSignatureForSelector:@selector(state)] retain]); base::scoped_nsobject invocation( [[NSInvocation invocationWithMethodSignature:signature] retain]); [invocation setTarget:peripheral_]; [invocation setSelector:@selector(state)]; [invocation invoke]; CBPeripheralState state = CBPeripheralStateDisconnected; [invocation getReturnValue:&state]; return state; }