bluetooth_classic_device_mac.mm 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // Copyright 2013 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.
  4. #include "device/bluetooth/bluetooth_classic_device_mac.h"
  5. #include <string>
  6. #include "base/bind.h"
  7. #include "base/hash/hash.h"
  8. #include "base/strings/string_number_conversions.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/strings/sys_string_conversions.h"
  11. #include "base/task/sequenced_task_runner.h"
  12. #include "base/time/time.h"
  13. #include "device/bluetooth/bluetooth_socket_mac.h"
  14. #include "device/bluetooth/public/cpp/bluetooth_address.h"
  15. #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
  16. // Undocumented API for accessing the Bluetooth transmit power level.
  17. // Similar to the API defined here [ http://goo.gl/20Q5vE ].
  18. @interface IOBluetoothHostController (UndocumentedAPI)
  19. - (IOReturn)
  20. BluetoothHCIReadTransmitPowerLevel:(BluetoothConnectionHandle)connection
  21. inType:(BluetoothHCITransmitPowerLevelType)type
  22. outTransmitPowerLevel:(BluetoothHCITransmitPowerLevel*)level;
  23. @end
  24. namespace device {
  25. namespace {
  26. const char kApiUnavailable[] = "This API is not implemented on this platform.";
  27. BluetoothUUID GetUuid(IOBluetoothSDPUUID* sdp_uuid) {
  28. DCHECK(sdp_uuid);
  29. const uint8_t* uuid_bytes =
  30. reinterpret_cast<const uint8_t*>([sdp_uuid bytes]);
  31. std::string uuid_str = base::HexEncode(uuid_bytes, 16);
  32. DCHECK_EQ(uuid_str.size(), 32U);
  33. uuid_str.insert(8, "-");
  34. uuid_str.insert(13, "-");
  35. uuid_str.insert(18, "-");
  36. uuid_str.insert(23, "-");
  37. return BluetoothUUID(uuid_str);
  38. }
  39. // Returns the first (should be, only) UUID contained within the
  40. // |service_class_data|. Returns an invalid (empty) UUID if none is found.
  41. BluetoothUUID ExtractUuid(IOBluetoothSDPDataElement* service_class_data) {
  42. NSArray* inner_elements = [service_class_data getArrayValue];
  43. for (IOBluetoothSDPDataElement* inner_element in inner_elements) {
  44. if ([inner_element getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID) {
  45. return GetUuid([[inner_element getUUIDValue] getUUIDWithLength:16]);
  46. }
  47. }
  48. return BluetoothUUID();
  49. }
  50. } // namespace
  51. BluetoothClassicDeviceMac::BluetoothClassicDeviceMac(
  52. BluetoothAdapterMac* adapter,
  53. IOBluetoothDevice* device)
  54. : BluetoothDeviceMac(adapter), device_([device retain]) {
  55. UpdateTimestamp();
  56. }
  57. BluetoothClassicDeviceMac::~BluetoothClassicDeviceMac() {
  58. }
  59. uint32_t BluetoothClassicDeviceMac::GetBluetoothClass() const {
  60. return [device_ classOfDevice];
  61. }
  62. void BluetoothClassicDeviceMac::CreateGattConnectionImpl(
  63. absl::optional<BluetoothUUID> service_uuid) {
  64. // Classic devices do not support GATT connection.
  65. DidConnectGatt(ERROR_UNSUPPORTED_DEVICE);
  66. }
  67. void BluetoothClassicDeviceMac::DisconnectGatt() {}
  68. std::string BluetoothClassicDeviceMac::GetAddress() const {
  69. return GetDeviceAddress(device_);
  70. }
  71. BluetoothDevice::AddressType BluetoothClassicDeviceMac::GetAddressType() const {
  72. NOTIMPLEMENTED();
  73. return ADDR_TYPE_UNKNOWN;
  74. }
  75. BluetoothDevice::VendorIDSource BluetoothClassicDeviceMac::GetVendorIDSource()
  76. const {
  77. return VENDOR_ID_UNKNOWN;
  78. }
  79. uint16_t BluetoothClassicDeviceMac::GetVendorID() const {
  80. return 0;
  81. }
  82. uint16_t BluetoothClassicDeviceMac::GetProductID() const {
  83. return 0;
  84. }
  85. uint16_t BluetoothClassicDeviceMac::GetDeviceID() const {
  86. return 0;
  87. }
  88. uint16_t BluetoothClassicDeviceMac::GetAppearance() const {
  89. // TODO(crbug.com/588083): Implementing GetAppearance()
  90. // on mac, win, and android platforms for chrome
  91. NOTIMPLEMENTED();
  92. return 0;
  93. }
  94. absl::optional<std::string> BluetoothClassicDeviceMac::GetName() const {
  95. if ([device_ name])
  96. return base::SysNSStringToUTF8([device_ name]);
  97. return absl::nullopt;
  98. }
  99. bool BluetoothClassicDeviceMac::IsPaired() const {
  100. return [device_ isPaired];
  101. }
  102. bool BluetoothClassicDeviceMac::IsConnected() const {
  103. return [device_ isConnected];
  104. }
  105. bool BluetoothClassicDeviceMac::IsGattConnected() const {
  106. return false; // Classic devices do not support GATT connection.
  107. }
  108. bool BluetoothClassicDeviceMac::IsConnectable() const {
  109. return false;
  110. }
  111. bool BluetoothClassicDeviceMac::IsConnecting() const {
  112. return false;
  113. }
  114. BluetoothDevice::UUIDSet BluetoothClassicDeviceMac::GetUUIDs() const {
  115. UUIDSet uuids;
  116. for (IOBluetoothSDPServiceRecord* service_record in [device_ services]) {
  117. IOBluetoothSDPDataElement* service_class_data =
  118. [service_record getAttributeDataElement:
  119. kBluetoothSDPAttributeIdentifierServiceClassIDList];
  120. auto type_descriptor = [service_class_data getTypeDescriptor];
  121. if (type_descriptor == kBluetoothSDPDataElementTypeUUID) {
  122. IOBluetoothSDPUUID* sdp_uuid =
  123. [[service_class_data getUUIDValue] getUUIDWithLength:16];
  124. BluetoothUUID uuid = GetUuid(sdp_uuid);
  125. if (uuid.IsValid())
  126. uuids.insert(uuid);
  127. } else if (type_descriptor ==
  128. kBluetoothSDPDataElementTypeDataElementSequence) {
  129. BluetoothUUID uuid = ExtractUuid(service_class_data);
  130. if (uuid.IsValid())
  131. uuids.insert(uuid);
  132. }
  133. }
  134. return uuids;
  135. }
  136. absl::optional<int8_t> BluetoothClassicDeviceMac::GetInquiryRSSI() const {
  137. return absl::nullopt;
  138. }
  139. absl::optional<int8_t> BluetoothClassicDeviceMac::GetInquiryTxPower() const {
  140. return absl::nullopt;
  141. }
  142. bool BluetoothClassicDeviceMac::ExpectingPinCode() const {
  143. NOTIMPLEMENTED();
  144. return false;
  145. }
  146. bool BluetoothClassicDeviceMac::ExpectingPasskey() const {
  147. NOTIMPLEMENTED();
  148. return false;
  149. }
  150. bool BluetoothClassicDeviceMac::ExpectingConfirmation() const {
  151. NOTIMPLEMENTED();
  152. return false;
  153. }
  154. void BluetoothClassicDeviceMac::GetConnectionInfo(
  155. ConnectionInfoCallback callback) {
  156. ConnectionInfo connection_info;
  157. if (![device_ isConnected]) {
  158. std::move(callback).Run(connection_info);
  159. return;
  160. }
  161. connection_info.rssi = [device_ rawRSSI];
  162. // The API guarantees that +127 is returned in case the RSSI is not readable:
  163. // http://goo.gl/bpURYv
  164. if (connection_info.rssi == 127)
  165. connection_info.rssi = kUnknownPower;
  166. connection_info.transmit_power =
  167. GetHostTransmitPower(kReadCurrentTransmitPowerLevel);
  168. connection_info.max_transmit_power =
  169. GetHostTransmitPower(kReadMaximumTransmitPowerLevel);
  170. std::move(callback).Run(connection_info);
  171. }
  172. void BluetoothClassicDeviceMac::SetConnectionLatency(
  173. ConnectionLatency connection_latency,
  174. base::OnceClosure callback,
  175. ErrorCallback error_callback) {
  176. NOTIMPLEMENTED();
  177. }
  178. void BluetoothClassicDeviceMac::Connect(PairingDelegate* pairing_delegate,
  179. ConnectCallback callback) {
  180. NOTIMPLEMENTED();
  181. }
  182. void BluetoothClassicDeviceMac::SetPinCode(const std::string& pincode) {
  183. NOTIMPLEMENTED();
  184. }
  185. void BluetoothClassicDeviceMac::SetPasskey(uint32_t passkey) {
  186. NOTIMPLEMENTED();
  187. }
  188. void BluetoothClassicDeviceMac::ConfirmPairing() {
  189. NOTIMPLEMENTED();
  190. }
  191. void BluetoothClassicDeviceMac::RejectPairing() {
  192. NOTIMPLEMENTED();
  193. }
  194. void BluetoothClassicDeviceMac::CancelPairing() {
  195. NOTIMPLEMENTED();
  196. }
  197. void BluetoothClassicDeviceMac::Disconnect(base::OnceClosure callback,
  198. ErrorCallback error_callback) {
  199. NOTIMPLEMENTED();
  200. }
  201. void BluetoothClassicDeviceMac::Forget(base::OnceClosure callback,
  202. ErrorCallback error_callback) {
  203. NOTIMPLEMENTED();
  204. }
  205. void BluetoothClassicDeviceMac::ConnectToService(
  206. const BluetoothUUID& uuid,
  207. ConnectToServiceCallback callback,
  208. ConnectToServiceErrorCallback error_callback) {
  209. scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
  210. socket->Connect(device_.get(), uuid,
  211. base::BindOnce(std::move(callback), socket),
  212. std::move(error_callback));
  213. }
  214. void BluetoothClassicDeviceMac::ConnectToServiceInsecurely(
  215. const BluetoothUUID& uuid,
  216. ConnectToServiceCallback callback,
  217. ConnectToServiceErrorCallback error_callback) {
  218. std::move(error_callback).Run(kApiUnavailable);
  219. }
  220. base::Time BluetoothClassicDeviceMac::GetLastUpdateTime() const {
  221. // getLastInquiryUpdate returns nil unpredictably so just use the
  222. // cross platform implementation of last update time.
  223. return last_update_time_;
  224. }
  225. int BluetoothClassicDeviceMac::GetHostTransmitPower(
  226. BluetoothHCITransmitPowerLevelType power_level_type) const {
  227. IOBluetoothHostController* controller =
  228. [IOBluetoothHostController defaultController];
  229. // Bail if the undocumented API is unavailable on this machine.
  230. SEL selector = @selector(BluetoothHCIReadTransmitPowerLevel:
  231. inType:
  232. outTransmitPowerLevel:);
  233. if (![controller respondsToSelector:selector])
  234. return kUnknownPower;
  235. BluetoothHCITransmitPowerLevel power_level;
  236. IOReturn result =
  237. [controller BluetoothHCIReadTransmitPowerLevel:[device_ connectionHandle]
  238. inType:power_level_type
  239. outTransmitPowerLevel:&power_level];
  240. if (result != kIOReturnSuccess)
  241. return kUnknownPower;
  242. return power_level;
  243. }
  244. // static
  245. std::string BluetoothClassicDeviceMac::GetDeviceAddress(
  246. IOBluetoothDevice* device) {
  247. return CanonicalizeBluetoothAddress(
  248. base::SysNSStringToUTF8([device addressString]));
  249. }
  250. bool BluetoothClassicDeviceMac::IsLowEnergyDevice() {
  251. return false;
  252. }
  253. } // namespace device