4aad7cf8032c392e9a8c2870b4e885c1a17d7496
[platform/framework/web/crosswalk.git] / src / device / bluetooth / bluetooth_device_mac.mm
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
5 #include "device/bluetooth/bluetooth_device_mac.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/hash.h"
12 #include "base/mac/sdk_forward_declarations.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "device/bluetooth/bluetooth_socket_mac.h"
18 #include "device/bluetooth/bluetooth_uuid.h"
19
20 // Undocumented API for accessing the Bluetooth transmit power level.
21 // Similar to the API defined here [ http://goo.gl/20Q5vE ].
22 @interface IOBluetoothHostController (UndocumentedAPI)
23 - (IOReturn)
24     BluetoothHCIReadTransmitPowerLevel:(BluetoothConnectionHandle)connection
25                                 inType:(BluetoothHCITransmitPowerLevelType)type
26                  outTransmitPowerLevel:(BluetoothHCITransmitPowerLevel*)level;
27 @end
28
29 namespace device {
30 namespace {
31
32 const char kApiUnavailable[] = "This API is not implemented on this platform.";
33
34 // Returns the first (should be, only) UUID contained within the
35 // |service_class_data|. Returns an invalid (empty) UUID if none is found.
36 BluetoothUUID ExtractUuid(IOBluetoothSDPDataElement* service_class_data) {
37   NSArray* inner_elements = [service_class_data getArrayValue];
38   IOBluetoothSDPUUID* sdp_uuid = nil;
39   for (IOBluetoothSDPDataElement* inner_element in inner_elements) {
40     if ([inner_element getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID) {
41       sdp_uuid = [[inner_element getUUIDValue] getUUIDWithLength:16];
42       break;
43     }
44   }
45
46   if (!sdp_uuid)
47     return BluetoothUUID();
48
49   const uint8* uuid_bytes = reinterpret_cast<const uint8*>([sdp_uuid bytes]);
50   std::string uuid_str = base::HexEncode(uuid_bytes, 16);
51   DCHECK_EQ(uuid_str.size(), 32U);
52   uuid_str.insert(8, "-");
53   uuid_str.insert(13, "-");
54   uuid_str.insert(18, "-");
55   uuid_str.insert(23, "-");
56   return BluetoothUUID(uuid_str);
57 }
58
59 }  // namespace
60
61 BluetoothDeviceMac::BluetoothDeviceMac(IOBluetoothDevice* device)
62     : device_([device retain]) {
63 }
64
65 BluetoothDeviceMac::~BluetoothDeviceMac() {
66 }
67
68 uint32 BluetoothDeviceMac::GetBluetoothClass() const {
69   return [device_ classOfDevice];
70 }
71
72 std::string BluetoothDeviceMac::GetDeviceName() const {
73   return base::SysNSStringToUTF8([device_ name]);
74 }
75
76 std::string BluetoothDeviceMac::GetAddress() const {
77   return GetDeviceAddress(device_);
78 }
79
80 BluetoothDevice::VendorIDSource BluetoothDeviceMac::GetVendorIDSource() const {
81   return VENDOR_ID_UNKNOWN;
82 }
83
84 uint16 BluetoothDeviceMac::GetVendorID() const {
85   return 0;
86 }
87
88 uint16 BluetoothDeviceMac::GetProductID() const {
89   return 0;
90 }
91
92 uint16 BluetoothDeviceMac::GetDeviceID() const {
93   return 0;
94 }
95
96 int BluetoothDeviceMac::GetRSSI() const {
97   if (![device_ isConnected]) {
98     NOTIMPLEMENTED();
99     return kUnknownPower;
100   }
101
102   int rssi = [device_ rawRSSI];
103
104   // The API guarantees that +127 is returned in case the RSSI is not readable:
105   // http://goo.gl/bpURYv
106   if (rssi == 127)
107     return kUnknownPower;
108
109   return rssi;
110 }
111
112 int BluetoothDeviceMac::GetCurrentHostTransmitPower() const {
113   return GetHostTransmitPower(kReadCurrentTransmitPowerLevel);
114 }
115
116 int BluetoothDeviceMac::GetMaximumHostTransmitPower() const {
117   return GetHostTransmitPower(kReadMaximumTransmitPowerLevel);
118 }
119
120 bool BluetoothDeviceMac::IsPaired() const {
121   return [device_ isPaired];
122 }
123
124 bool BluetoothDeviceMac::IsConnected() const {
125   return [device_ isConnected];
126 }
127
128 bool BluetoothDeviceMac::IsConnectable() const {
129   return false;
130 }
131
132 bool BluetoothDeviceMac::IsConnecting() const {
133   return false;
134 }
135
136 BluetoothDevice::UUIDList BluetoothDeviceMac::GetUUIDs() const {
137   UUIDList uuids;
138   for (IOBluetoothSDPServiceRecord* service_record in [device_ services]) {
139     IOBluetoothSDPDataElement* service_class_data =
140         [service_record getAttributeDataElement:
141             kBluetoothSDPAttributeIdentifierServiceClassIDList];
142     if ([service_class_data getTypeDescriptor] ==
143             kBluetoothSDPDataElementTypeDataElementSequence) {
144       BluetoothUUID uuid = ExtractUuid(service_class_data);
145       if (uuid.IsValid())
146         uuids.push_back(uuid);
147     }
148   }
149   return uuids;
150 }
151
152 bool BluetoothDeviceMac::ExpectingPinCode() const {
153   NOTIMPLEMENTED();
154   return false;
155 }
156
157 bool BluetoothDeviceMac::ExpectingPasskey() const {
158   NOTIMPLEMENTED();
159   return false;
160 }
161
162 bool BluetoothDeviceMac::ExpectingConfirmation() const {
163   NOTIMPLEMENTED();
164   return false;
165 }
166
167 void BluetoothDeviceMac::Connect(
168     PairingDelegate* pairing_delegate,
169     const base::Closure& callback,
170     const ConnectErrorCallback& error_callback) {
171   NOTIMPLEMENTED();
172 }
173
174 void BluetoothDeviceMac::SetPinCode(const std::string& pincode) {
175   NOTIMPLEMENTED();
176 }
177
178 void BluetoothDeviceMac::SetPasskey(uint32 passkey) {
179   NOTIMPLEMENTED();
180 }
181
182 void BluetoothDeviceMac::ConfirmPairing() {
183   NOTIMPLEMENTED();
184 }
185
186 void BluetoothDeviceMac::RejectPairing() {
187   NOTIMPLEMENTED();
188 }
189
190 void BluetoothDeviceMac::CancelPairing() {
191   NOTIMPLEMENTED();
192 }
193
194 void BluetoothDeviceMac::Disconnect(const base::Closure& callback,
195                                     const ErrorCallback& error_callback) {
196   NOTIMPLEMENTED();
197 }
198
199 void BluetoothDeviceMac::Forget(const ErrorCallback& error_callback) {
200   NOTIMPLEMENTED();
201 }
202
203 void BluetoothDeviceMac::ConnectToService(
204     const BluetoothUUID& uuid,
205     const ConnectToServiceCallback& callback,
206     const ConnectToServiceErrorCallback& error_callback) {
207   scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
208   socket->Connect(
209       device_.get(), uuid, base::Bind(callback, socket), error_callback);
210 }
211
212 void BluetoothDeviceMac::ConnectToServiceInsecurely(
213       const BluetoothUUID& uuid,
214       const ConnectToServiceCallback& callback,
215       const ConnectToServiceErrorCallback& error_callback) {
216   error_callback.Run(kApiUnavailable);
217 }
218
219 void BluetoothDeviceMac::CreateGattConnection(
220       const GattConnectionCallback& callback,
221       const ConnectErrorCallback& error_callback) {
222   // TODO(armansito): Implement.
223   error_callback.Run(ERROR_UNSUPPORTED_DEVICE);
224 }
225
226 void BluetoothDeviceMac::StartConnectionMonitor(
227     const base::Closure& callback,
228     const ErrorCallback& error_callback) {
229   NOTIMPLEMENTED();
230 }
231
232 NSDate* BluetoothDeviceMac::GetLastInquiryUpdate() {
233   return [device_ getLastInquiryUpdate];
234 }
235
236 int BluetoothDeviceMac::GetHostTransmitPower(
237     BluetoothHCITransmitPowerLevelType power_level_type) const {
238   IOBluetoothHostController* controller =
239       [IOBluetoothHostController defaultController];
240
241   // Bail if the undocumented API is unavailable on this machine.
242   SEL selector = @selector(
243       BluetoothHCIReadTransmitPowerLevel:inType:outTransmitPowerLevel:);
244   if (![controller respondsToSelector:selector])
245     return kUnknownPower;
246
247   BluetoothHCITransmitPowerLevel power_level;
248   IOReturn result =
249       [controller BluetoothHCIReadTransmitPowerLevel:[device_ connectionHandle]
250                                               inType:power_level_type
251                                outTransmitPowerLevel:&power_level];
252   if (result != kIOReturnSuccess)
253     return kUnknownPower;
254
255   return power_level;
256 }
257
258 // static
259 std::string BluetoothDeviceMac::GetDeviceAddress(IOBluetoothDevice* device) {
260   return CanonicalizeAddress(base::SysNSStringToUTF8([device addressString]));
261 }
262
263 }  // namespace device