#include "device/bluetooth/bluetooth_device_mac.h"
-#include <IOBluetooth/Bluetooth.h>
-#import <IOBluetooth/objc/IOBluetoothDevice.h>
-#import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
-#import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
-
#include <string>
#include "base/basictypes.h"
+#include "base/bind.h"
#include "base/hash.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
+#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
-#include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
-#include "device/bluetooth/bluetooth_profile_mac.h"
-#include "device/bluetooth/bluetooth_service_record_mac.h"
#include "device/bluetooth/bluetooth_socket_mac.h"
-
-// Replicate specific 10.7 SDK declarations for building with prior SDKs.
-#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
-@interface IOBluetoothDevice (LionSDKDeclarations)
-- (NSString*)addressString;
-- (NSString*)name;
-- (unsigned int)classOfDevice;
-- (NSArray*)services;
+#include "device/bluetooth/bluetooth_uuid.h"
+
+// Undocumented API for accessing the Bluetooth transmit power level.
+// Similar to the API defined here [ http://goo.gl/20Q5vE ].
+@interface IOBluetoothHostController (UndocumentedAPI)
+- (IOReturn)
+ BluetoothHCIReadTransmitPowerLevel:(BluetoothConnectionHandle)connection
+ inType:(BluetoothHCITransmitPowerLevelType)type
+ outTransmitPowerLevel:(BluetoothHCITransmitPowerLevel*)level;
@end
-#endif // MAC_OS_X_VERSION_10_7
-
+namespace device {
namespace {
-// Converts |uuid| to a IOBluetoothSDPUUID instance.
-//
-// |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
-IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) {
- DCHECK(uuid.size() == 36);
- DCHECK(uuid[8] == '-');
- DCHECK(uuid[13] == '-');
- DCHECK(uuid[18] == '-');
- DCHECK(uuid[23] == '-');
- std::string numbers_only = uuid;
- numbers_only.erase(23, 1);
- numbers_only.erase(18, 1);
- numbers_only.erase(13, 1);
- numbers_only.erase(8, 1);
- std::vector<uint8> uuid_bytes_vector;
- base::HexStringToBytes(numbers_only, &uuid_bytes_vector);
- DCHECK(uuid_bytes_vector.size() == 16);
-
- return [IOBluetoothSDPUUID uuidWithBytes:&uuid_bytes_vector[0]
- length:uuid_bytes_vector.size()];
+// Returns the first (should be, only) UUID contained within the
+// |service_class_data|. Returns an invalid (empty) UUID if none is found.
+BluetoothUUID ExtractUuid(IOBluetoothSDPDataElement* service_class_data) {
+ NSArray* inner_elements = [service_class_data getArrayValue];
+ IOBluetoothSDPUUID* sdp_uuid = nil;
+ for (IOBluetoothSDPDataElement* inner_element in inner_elements) {
+ if ([inner_element getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID) {
+ sdp_uuid = [[inner_element getUUIDValue] getUUIDWithLength:16];
+ break;
+ }
+ }
+
+ if (!sdp_uuid)
+ return BluetoothUUID();
+
+ const uint8* uuid_bytes = reinterpret_cast<const uint8*>([sdp_uuid bytes]);
+ std::string uuid_str = base::HexEncode(uuid_bytes, 16);
+ DCHECK_EQ(uuid_str.size(), 32U);
+ uuid_str.insert(8, "-");
+ uuid_str.insert(13, "-");
+ uuid_str.insert(18, "-");
+ uuid_str.insert(23, "-");
+ return BluetoothUUID(uuid_str);
}
} // namespace
-namespace device {
-
BluetoothDeviceMac::BluetoothDeviceMac(IOBluetoothDevice* device)
- : BluetoothDevice(), device_([device retain]) {
+ : device_([device retain]) {
}
BluetoothDeviceMac::~BluetoothDeviceMac() {
- [device_ release];
}
uint32 BluetoothDeviceMac::GetBluetoothClass() const {
}
std::string BluetoothDeviceMac::GetAddress() const {
- return base::SysNSStringToUTF8([device_ addressString]);
+ return GetDeviceAddress(device_);
}
-BluetoothDevice::VendorIDSource
-BluetoothDeviceMac::GetVendorIDSource() const {
+BluetoothDevice::VendorIDSource BluetoothDeviceMac::GetVendorIDSource() const {
return VENDOR_ID_UNKNOWN;
}
return 0;
}
+int BluetoothDeviceMac::GetRSSI() const {
+ if (![device_ isConnected]) {
+ NOTIMPLEMENTED();
+ return kUnknownPower;
+ }
+
+ int rssi = [device_ rawRSSI];
+
+ // The API guarantees that +127 is returned in case the RSSI is not readable:
+ // http://goo.gl/bpURYv
+ if (rssi == 127)
+ return kUnknownPower;
+
+ return rssi;
+}
+
+int BluetoothDeviceMac::GetCurrentHostTransmitPower() const {
+ return GetHostTransmitPower(kReadCurrentTransmitPowerLevel);
+}
+
+int BluetoothDeviceMac::GetMaximumHostTransmitPower() const {
+ return GetHostTransmitPower(kReadMaximumTransmitPowerLevel);
+}
+
bool BluetoothDeviceMac::IsPaired() const {
return [device_ isPaired];
}
return false;
}
-// TODO(keybuk): BluetoothServiceRecord is deprecated; implement this method
-// without using BluetoothServiceRecord.
BluetoothDevice::UUIDList BluetoothDeviceMac::GetUUIDs() const {
UUIDList uuids;
- for (IOBluetoothSDPServiceRecord* service in [device_ services]) {
- BluetoothServiceRecordMac service_record(service);
- uuids.push_back(service_record.uuid());
+ for (IOBluetoothSDPServiceRecord* service_record in [device_ services]) {
+ IOBluetoothSDPDataElement* service_class_data =
+ [service_record getAttributeDataElement:
+ kBluetoothSDPAttributeIdentifierServiceClassIDList];
+ if ([service_class_data getTypeDescriptor] ==
+ kBluetoothSDPDataElementTypeDataElementSequence) {
+ BluetoothUUID uuid = ExtractUuid(service_class_data);
+ if (uuid.IsValid())
+ uuids.push_back(uuid);
+ }
}
return uuids;
}
NOTIMPLEMENTED();
}
-void BluetoothDeviceMac::Disconnect(
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
+void BluetoothDeviceMac::Disconnect(const base::Closure& callback,
+ const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
}
void BluetoothDeviceMac::ConnectToService(
- const std::string& service_uuid,
- const SocketCallback& callback) {
- IOBluetoothSDPServiceRecord* record =
- [device_ getServiceRecordForUUID:GetIOBluetoothSDPUUID(service_uuid)];
- if (record != nil) {
- BluetoothServiceRecordMac service_record(record);
- scoped_refptr<BluetoothSocket> socket(
- BluetoothSocketMac::CreateBluetoothSocket(service_record));
- if (socket.get() != NULL)
- callback.Run(socket);
- }
+ const BluetoothUUID& uuid,
+ const ConnectToServiceCallback& callback,
+ const ConnectToServiceErrorCallback& error_callback) {
+ scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
+ socket->Connect(
+ device_.get(), uuid, base::Bind(callback, socket), error_callback);
}
-void BluetoothDeviceMac::ConnectToProfile(
- device::BluetoothProfile* profile,
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
- if (static_cast<BluetoothProfileMac*>(profile)->Connect(device_))
- callback.Run();
- else
- error_callback.Run();
+void BluetoothDeviceMac::CreateGattConnection(
+ const GattConnectionCallback& callback,
+ const ConnectErrorCallback& error_callback) {
+ // TODO(armansito): Implement.
+ error_callback.Run(ERROR_UNSUPPORTED_DEVICE);
}
-void BluetoothDeviceMac::SetOutOfBandPairingData(
- const BluetoothOutOfBandPairingData& data,
+void BluetoothDeviceMac::StartConnectionMonitor(
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
-void BluetoothDeviceMac::ClearOutOfBandPairingData(
- const base::Closure& callback,
- const ErrorCallback& error_callback) {
- NOTIMPLEMENTED();
+NSDate* BluetoothDeviceMac::GetLastInquiryUpdate() {
+ return [device_ getLastInquiryUpdate];
+}
+
+int BluetoothDeviceMac::GetHostTransmitPower(
+ BluetoothHCITransmitPowerLevelType power_level_type) const {
+ IOBluetoothHostController* controller =
+ [IOBluetoothHostController defaultController];
+
+ // Bail if the undocumented API is unavailable on this machine.
+ SEL selector = @selector(
+ BluetoothHCIReadTransmitPowerLevel:inType:outTransmitPowerLevel:);
+ if (![controller respondsToSelector:selector])
+ return kUnknownPower;
+
+ BluetoothHCITransmitPowerLevel power_level;
+ IOReturn result =
+ [controller BluetoothHCIReadTransmitPowerLevel:[device_ connectionHandle]
+ inType:power_level_type
+ outTransmitPowerLevel:&power_level];
+ if (result != kIOReturnSuccess)
+ return kUnknownPower;
+
+ return power_level;
+}
+
+// static
+std::string BluetoothDeviceMac::GetDeviceAddress(IOBluetoothDevice* device) {
+ return CanonicalizeAddress(base::SysNSStringToUTF8([device addressString]));
}
} // namespace device