OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/bluetooth/bluetooth_adapter_mac.h" | 5 #include "device/bluetooth/bluetooth_adapter_mac.h" |
6 | 6 |
7 #import <IOBluetooth/objc/IOBluetoothDevice.h> | 7 #import <IOBluetooth/objc/IOBluetoothDevice.h> |
8 #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h> | |
9 #import <IOBluetooth/objc/IOBluetoothHostController.h> | 8 #import <IOBluetooth/objc/IOBluetoothHostController.h> |
10 | 9 |
11 #include <string> | 10 #include <string> |
12 | 11 |
13 #include "base/bind.h" | 12 #include "base/bind.h" |
14 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
15 #include "base/containers/hash_tables.h" | 14 #include "base/containers/hash_tables.h" |
16 #include "base/location.h" | 15 #include "base/location.h" |
17 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
18 #include "base/sequenced_task_runner.h" | 17 #include "base/sequenced_task_runner.h" |
19 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
20 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
21 #include "base/thread_task_runner_handle.h" | 20 #include "base/thread_task_runner_handle.h" |
22 #include "base/time/time.h" | 21 #include "base/time/time.h" |
23 #include "device/bluetooth/bluetooth_device_mac.h" | 22 #include "device/bluetooth/bluetooth_device_mac.h" |
24 #include "device/bluetooth/bluetooth_socket_mac.h" | 23 #include "device/bluetooth/bluetooth_socket_mac.h" |
25 #include "device/bluetooth/bluetooth_uuid.h" | 24 #include "device/bluetooth/bluetooth_uuid.h" |
26 | 25 |
27 // Replicate specific 10.7 SDK declarations for building with prior SDKs. | 26 // Replicate specific 10.7 SDK declarations for building with prior SDKs. |
28 #if !defined(MAC_OS_X_VERSION_10_7) || \ | 27 #if !defined(MAC_OS_X_VERSION_10_7) || \ |
29 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 | 28 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
30 | 29 |
31 @interface IOBluetoothHostController (LionSDKDeclarations) | 30 @interface IOBluetoothHostController (LionSDKDeclarations) |
32 - (NSString*)nameAsString; | 31 - (NSString*)nameAsString; |
33 - (BluetoothHCIPowerState)powerState; | 32 - (BluetoothHCIPowerState)powerState; |
34 @end | 33 @end |
35 | 34 |
36 @protocol IOBluetoothDeviceInquiryDelegate | |
37 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender; | |
38 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
39 device:(IOBluetoothDevice*)device; | |
40 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
41 error:(IOReturn)error | |
42 aborted:(BOOL)aborted; | |
43 @end | |
44 | |
45 #endif // MAC_OS_X_VERSION_10_7 | 35 #endif // MAC_OS_X_VERSION_10_7 |
46 | 36 |
47 @interface BluetoothAdapterMacDelegate | |
48 : NSObject <IOBluetoothDeviceInquiryDelegate> { | |
49 @private | |
50 device::BluetoothAdapterMac* adapter_; // weak | |
51 } | |
52 | |
53 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter; | |
54 | |
55 @end | |
56 | |
57 @implementation BluetoothAdapterMacDelegate | |
58 | |
59 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter { | |
60 if ((self = [super init])) | |
61 adapter_ = adapter; | |
62 | |
63 return self; | |
64 } | |
65 | |
66 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender { | |
67 adapter_->DeviceInquiryStarted(sender); | |
68 } | |
69 | |
70 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
71 device:(IOBluetoothDevice*)device { | |
72 adapter_->DeviceFound(sender, device); | |
73 } | |
74 | |
75 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
76 error:(IOReturn)error | |
77 aborted:(BOOL)aborted { | |
78 adapter_->DeviceInquiryComplete(sender, error, aborted); | |
79 } | |
80 | |
81 @end | |
82 | |
83 namespace { | 37 namespace { |
84 | 38 |
85 const int kPollIntervalMs = 500; | 39 const int kPollIntervalMs = 500; |
86 | 40 |
87 } // namespace | 41 } // namespace |
88 | 42 |
89 namespace device { | 43 namespace device { |
90 | 44 |
91 // static | 45 // static |
92 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( | 46 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( |
93 const InitCallback& init_callback) { | 47 const InitCallback& init_callback) { |
94 return BluetoothAdapterMac::CreateAdapter(); | 48 return BluetoothAdapterMac::CreateAdapter(); |
95 } | 49 } |
96 | 50 |
97 // static | 51 // static |
98 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { | 52 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { |
99 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); | 53 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); |
100 adapter->Init(); | 54 adapter->Init(); |
101 return adapter->weak_ptr_factory_.GetWeakPtr(); | 55 return adapter->weak_ptr_factory_.GetWeakPtr(); |
102 } | 56 } |
103 | 57 |
104 BluetoothAdapterMac::BluetoothAdapterMac() | 58 BluetoothAdapterMac::BluetoothAdapterMac() |
105 : BluetoothAdapter(), | 59 : BluetoothAdapter(), |
106 powered_(false), | 60 powered_(false), |
107 discovery_status_(NOT_DISCOVERING), | 61 num_discovery_sessions_(0), |
108 adapter_delegate_( | 62 classic_discovery_manager_(BluetoothDiscoveryManagerMac::CreateClassic()), |
109 [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]), | |
110 device_inquiry_( | |
111 [[IOBluetoothDeviceInquiry | |
112 inquiryWithDelegate:adapter_delegate_] retain]), | |
113 weak_ptr_factory_(this) { | 63 weak_ptr_factory_(this) { |
64 DCHECK(classic_discovery_manager_.get()); | |
65 classic_discovery_manager_->AddObserver(this); | |
114 } | 66 } |
115 | 67 |
116 BluetoothAdapterMac::~BluetoothAdapterMac() { | 68 BluetoothAdapterMac::~BluetoothAdapterMac() { |
69 classic_discovery_manager_->RemoveObserver(this); | |
117 } | 70 } |
118 | 71 |
119 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { | 72 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { |
120 DCHECK(observer); | 73 DCHECK(observer); |
121 observers_.AddObserver(observer); | 74 observers_.AddObserver(observer); |
122 } | 75 } |
123 | 76 |
124 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) { | 77 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) { |
125 DCHECK(observer); | 78 DCHECK(observer); |
126 observers_.RemoveObserver(observer); | 79 observers_.RemoveObserver(observer); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
164 } | 117 } |
165 | 118 |
166 void BluetoothAdapterMac::SetDiscoverable( | 119 void BluetoothAdapterMac::SetDiscoverable( |
167 bool discoverable, | 120 bool discoverable, |
168 const base::Closure& callback, | 121 const base::Closure& callback, |
169 const ErrorCallback& error_callback) { | 122 const ErrorCallback& error_callback) { |
170 NOTIMPLEMENTED(); | 123 NOTIMPLEMENTED(); |
171 } | 124 } |
172 | 125 |
173 bool BluetoothAdapterMac::IsDiscovering() const { | 126 bool BluetoothAdapterMac::IsDiscovering() const { |
174 return discovery_status_ == DISCOVERING || | 127 return classic_discovery_manager_->IsDiscovering(); |
175 discovery_status_ == DISCOVERY_STOPPING; | |
176 } | 128 } |
177 | 129 |
178 void BluetoothAdapterMac::CreateRfcommService( | 130 void BluetoothAdapterMac::CreateRfcommService( |
179 const BluetoothUUID& uuid, | 131 const BluetoothUUID& uuid, |
180 int channel, | 132 int channel, |
181 bool insecure, | 133 bool insecure, |
182 const CreateServiceCallback& callback, | 134 const CreateServiceCallback& callback, |
183 const CreateServiceErrorCallback& error_callback) { | 135 const CreateServiceErrorCallback& error_callback) { |
184 // TODO(keybuk): implement. | 136 // TODO(keybuk): implement. |
185 NOTIMPLEMENTED(); | 137 NOTIMPLEMENTED(); |
186 } | 138 } |
187 | 139 |
188 void BluetoothAdapterMac::CreateL2capService( | 140 void BluetoothAdapterMac::CreateL2capService( |
189 const BluetoothUUID& uuid, | 141 const BluetoothUUID& uuid, |
190 int psm, | 142 int psm, |
191 const CreateServiceCallback& callback, | 143 const CreateServiceCallback& callback, |
192 const CreateServiceErrorCallback& error_callback) { | 144 const CreateServiceErrorCallback& error_callback) { |
193 // TODO(keybuk): implement. | 145 // TODO(keybuk): implement. |
194 NOTIMPLEMENTED(); | 146 NOTIMPLEMENTED(); |
195 } | 147 } |
196 | 148 |
149 void BluetoothAdapterMac::DeviceFound(BluetoothDiscoveryManagerMac* manager, | |
150 IOBluetoothDevice* device) { | |
151 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
152 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
153 BluetoothDeviceMac device_mac(device); | |
154 FOR_EACH_OBSERVER( | |
155 BluetoothAdapter::Observer, observers_, DeviceAdded(this, &device_mac)); | |
156 discovered_devices_.insert(device_address); | |
157 } | |
158 } | |
159 | |
160 void BluetoothAdapterMac::DiscoveryStopped( | |
161 BluetoothDiscoveryManagerMac* manager, | |
162 bool unexpected) { | |
163 DCHECK(manager == classic_discovery_manager_.get()); | |
Ilya Sherman
2014/06/10 23:23:01
nit: DCHECK_EQ
armansito
2014/06/13 02:14:54
Done.
| |
164 if (unexpected) { | |
165 DVLOG(1) << "Discovery stopped unexpectedly"; | |
166 num_discovery_sessions_ = 0; | |
167 MarkDiscoverySessionsAsInactive(); | |
168 } | |
169 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, | |
170 observers_, | |
171 AdapterDiscoveringChanged(this, false)); | |
172 } | |
173 | |
197 void BluetoothAdapterMac::AddDiscoverySession( | 174 void BluetoothAdapterMac::AddDiscoverySession( |
198 const base::Closure& callback, | 175 const base::Closure& callback, |
199 const ErrorCallback& error_callback) { | 176 const ErrorCallback& error_callback) { |
200 if (discovery_status_ == DISCOVERING) { | 177 DVLOG(1) << __func__; |
201 num_discovery_listeners_++; | 178 if (num_discovery_sessions_ > 0) { |
179 DCHECK(IsDiscovering()); | |
180 num_discovery_sessions_++; | |
202 callback.Run(); | 181 callback.Run(); |
203 return; | 182 return; |
204 } | 183 } |
205 on_start_discovery_callbacks_.push_back( | 184 |
206 std::make_pair(callback, error_callback)); | 185 DCHECK_EQ(0, num_discovery_sessions_); |
207 MaybeStartDeviceInquiry(); | 186 |
187 if (!classic_discovery_manager_->StartDiscovery()) { | |
188 DVLOG(1) << "Failed to add a discovery session"; | |
189 error_callback.Run(); | |
190 return; | |
191 } | |
192 | |
193 DVLOG(1) << "Added a discovery session"; | |
194 num_discovery_sessions_++; | |
195 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, | |
196 observers_, | |
197 AdapterDiscoveringChanged(this, true)); | |
198 callback.Run(); | |
208 } | 199 } |
209 | 200 |
210 void BluetoothAdapterMac::RemoveDiscoverySession( | 201 void BluetoothAdapterMac::RemoveDiscoverySession( |
211 const base::Closure& callback, | 202 const base::Closure& callback, |
212 const ErrorCallback& error_callback) { | 203 const ErrorCallback& error_callback) { |
213 if (discovery_status_ == NOT_DISCOVERING) { | 204 DVLOG(1) << __func__; |
205 | |
206 if (num_discovery_sessions_ > 1) { | |
207 // There are active sessions other than the one currently being removed. | |
208 DCHECK(IsDiscovering()); | |
209 num_discovery_sessions_--; | |
210 callback.Run(); | |
211 return; | |
212 } | |
213 | |
214 if (num_discovery_sessions_ == 0) { | |
215 DVLOG(1) << "No active discovery sessions. Returning error."; | |
214 error_callback.Run(); | 216 error_callback.Run(); |
215 return; | 217 return; |
216 } | 218 } |
217 on_stop_discovery_callbacks_.push_back( | 219 |
218 std::make_pair(callback, error_callback)); | 220 if (!classic_discovery_manager_->StopDiscovery()) { |
219 MaybeStopDeviceInquiry(); | 221 DVLOG(1) << "Failed to stop discovery"; |
222 error_callback.Run(); | |
223 return; | |
224 } | |
225 | |
226 DVLOG(1) << "Discovery stopped"; | |
227 num_discovery_sessions_--; | |
228 callback.Run(); | |
220 } | 229 } |
221 | 230 |
222 void BluetoothAdapterMac::RemovePairingDelegateInternal( | 231 void BluetoothAdapterMac::RemovePairingDelegateInternal( |
223 BluetoothDevice::PairingDelegate* pairing_delegate) { | 232 BluetoothDevice::PairingDelegate* pairing_delegate) { |
224 } | 233 } |
225 | 234 |
226 void BluetoothAdapterMac::Init() { | 235 void BluetoothAdapterMac::Init() { |
227 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 236 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
228 PollAdapter(); | 237 PollAdapter(); |
229 } | 238 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 } | 284 } |
276 | 285 |
277 ui_task_runner_->PostDelayedTask( | 286 ui_task_runner_->PostDelayedTask( |
278 FROM_HERE, | 287 FROM_HERE, |
279 base::Bind(&BluetoothAdapterMac::PollAdapter, | 288 base::Bind(&BluetoothAdapterMac::PollAdapter, |
280 weak_ptr_factory_.GetWeakPtr()), | 289 weak_ptr_factory_.GetWeakPtr()), |
281 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); | 290 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); |
282 } | 291 } |
283 | 292 |
284 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { | 293 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { |
294 // TODO(armansito): This code never calls | |
295 // BluetoothAdapter::Observer::DeviceRemoved. It should, if a device | |
296 // no longer exists. | |
285 STLDeleteValues(&devices_); | 297 STLDeleteValues(&devices_); |
286 for (IOBluetoothDevice* device in devices) { | 298 for (IOBluetoothDevice* device in devices) { |
287 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | 299 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); |
288 devices_[device_address] = new BluetoothDeviceMac(device); | 300 devices_[device_address] = new BluetoothDeviceMac(device); |
289 } | 301 } |
290 } | 302 } |
291 | 303 |
292 void BluetoothAdapterMac::DeviceInquiryStarted( | |
293 IOBluetoothDeviceInquiry* inquiry) { | |
294 DCHECK_EQ(device_inquiry_, inquiry); | |
295 if (discovery_status_ == DISCOVERING) | |
296 return; | |
297 | |
298 discovery_status_ = DISCOVERING; | |
299 RunCallbacks(on_start_discovery_callbacks_, true); | |
300 num_discovery_listeners_ = on_start_discovery_callbacks_.size(); | |
301 on_start_discovery_callbacks_.clear(); | |
302 | |
303 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
304 AdapterDiscoveringChanged(this, true)); | |
305 MaybeStopDeviceInquiry(); | |
306 } | |
307 | |
308 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry, | |
309 IOBluetoothDevice* device) { | |
310 DCHECK_EQ(device_inquiry_, inquiry); | |
311 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
312 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
313 BluetoothDeviceMac device_mac(device); | |
314 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
315 DeviceAdded(this, &device_mac)); | |
316 discovered_devices_.insert(device_address); | |
317 } | |
318 } | |
319 | |
320 void BluetoothAdapterMac::DeviceInquiryComplete( | |
321 IOBluetoothDeviceInquiry* inquiry, | |
322 IOReturn error, | |
323 bool aborted) { | |
324 DCHECK_EQ(device_inquiry_, inquiry); | |
325 if (discovery_status_ == DISCOVERING && | |
326 [device_inquiry_ start] == kIOReturnSuccess) { | |
327 return; | |
328 } | |
329 | |
330 // Device discovery is done. | |
331 discovered_devices_.clear(); | |
332 discovery_status_ = NOT_DISCOVERING; | |
333 RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess); | |
334 num_discovery_listeners_ = 0; | |
335 on_stop_discovery_callbacks_.clear(); | |
336 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
337 AdapterDiscoveringChanged(this, false)); | |
338 MaybeStartDeviceInquiry(); | |
339 } | |
340 | |
341 void BluetoothAdapterMac::MaybeStartDeviceInquiry() { | |
342 if (discovery_status_ == NOT_DISCOVERING && | |
343 !on_start_discovery_callbacks_.empty()) { | |
344 discovery_status_ = DISCOVERY_STARTING; | |
345 if ([device_inquiry_ start] != kIOReturnSuccess) { | |
346 discovery_status_ = NOT_DISCOVERING; | |
347 RunCallbacks(on_start_discovery_callbacks_, false); | |
348 on_start_discovery_callbacks_.clear(); | |
349 } | |
350 } | |
351 } | |
352 | |
353 void BluetoothAdapterMac::MaybeStopDeviceInquiry() { | |
354 if (discovery_status_ != DISCOVERING) | |
355 return; | |
356 | |
357 if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) { | |
358 RunCallbacks(on_stop_discovery_callbacks_, true); | |
359 num_discovery_listeners_ -= on_stop_discovery_callbacks_.size(); | |
360 on_stop_discovery_callbacks_.clear(); | |
361 return; | |
362 } | |
363 | |
364 discovery_status_ = DISCOVERY_STOPPING; | |
365 if ([device_inquiry_ stop] != kIOReturnSuccess) { | |
366 RunCallbacks(on_stop_discovery_callbacks_, false); | |
367 on_stop_discovery_callbacks_.clear(); | |
368 } | |
369 } | |
370 | |
371 void BluetoothAdapterMac::RunCallbacks( | |
372 const DiscoveryCallbackList& callback_list, bool success) const { | |
373 for (DiscoveryCallbackList::const_iterator iter = callback_list.begin(); | |
374 iter != callback_list.end(); | |
375 ++iter) { | |
376 if (success) | |
377 ui_task_runner_->PostTask(FROM_HERE, iter->first); | |
378 else | |
379 ui_task_runner_->PostTask(FROM_HERE, iter->second); | |
380 } | |
381 } | |
382 | |
383 } // namespace device | 304 } // namespace device |
OLD | NEW |