Remove the locks in shared renderer state.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_mac.mm
blob9ac7caaea01f6712e841e769a10197a7b19a6d7a
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.
5 #include "device/bluetooth/bluetooth_adapter_mac.h"
7 #import <IOBluetooth/objc/IOBluetoothDevice.h>
8 #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
9 #import <IOBluetooth/objc/IOBluetoothHostController.h>
11 #include <string>
13 #include "base/bind.h"
14 #include "base/compiler_specific.h"
15 #include "base/containers/hash_tables.h"
16 #include "base/location.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/sys_string_conversions.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "base/time/time.h"
23 #include "device/bluetooth/bluetooth_device_mac.h"
25 // Replicate specific 10.7 SDK declarations for building with prior SDKs.
26 #if !defined(MAC_OS_X_VERSION_10_7) || \
27 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
29 @interface IOBluetoothHostController (LionSDKDeclarations)
30 - (NSString*)nameAsString;
31 - (BluetoothHCIPowerState)powerState;
32 @end
34 @interface IOBluetoothDevice (LionSDKDeclarations)
35 - (NSString*)addressString;
36 @end
38 @protocol IOBluetoothDeviceInquiryDelegate
39 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
40 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
41                           device:(IOBluetoothDevice*)device;
42 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
43                         error:(IOReturn)error
44                       aborted:(BOOL)aborted;
45 @end
47 #endif  // MAC_OS_X_VERSION_10_7
49 @interface BluetoothAdapterMacDelegate
50     : NSObject <IOBluetoothDeviceInquiryDelegate> {
51  @private
52   device::BluetoothAdapterMac* adapter_;  // weak
55 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter;
57 @end
59 @implementation BluetoothAdapterMacDelegate
61 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter {
62   if ((self = [super init]))
63     adapter_ = adapter;
65   return self;
68 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender {
69   adapter_->DeviceInquiryStarted(sender);
72 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
73                           device:(IOBluetoothDevice*)device {
74   adapter_->DeviceFound(sender, device);
77 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
78                         error:(IOReturn)error
79                       aborted:(BOOL)aborted {
80   adapter_->DeviceInquiryComplete(sender, error, aborted);
83 @end
85 namespace {
87 const int kPollIntervalMs = 500;
89 }  // namespace
91 namespace device {
93 BluetoothAdapterMac::BluetoothAdapterMac()
94     : BluetoothAdapter(),
95       powered_(false),
96       discovery_status_(NOT_DISCOVERING),
97       adapter_delegate_(
98           [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]),
99       device_inquiry_(
100           [[IOBluetoothDeviceInquiry
101               inquiryWithDelegate:adapter_delegate_] retain]),
102       recently_accessed_device_timestamp_(nil),
103       weak_ptr_factory_(this) {
106 BluetoothAdapterMac::~BluetoothAdapterMac() {
107   [device_inquiry_ release];
108   [adapter_delegate_ release];
109   [recently_accessed_device_timestamp_ release];
112 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) {
113   DCHECK(observer);
114   observers_.AddObserver(observer);
117 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) {
118   DCHECK(observer);
119   observers_.RemoveObserver(observer);
122 std::string BluetoothAdapterMac::GetAddress() const {
123   return address_;
126 std::string BluetoothAdapterMac::GetName() const {
127   return name_;
130 void BluetoothAdapterMac::SetName(const std::string& name,
131                                   const base::Closure& callback,
132                                   const ErrorCallback& error_callback) {
133   NOTIMPLEMENTED();
136 bool BluetoothAdapterMac::IsInitialized() const {
137   return true;
140 bool BluetoothAdapterMac::IsPresent() const {
141   return !address_.empty();
144 bool BluetoothAdapterMac::IsPowered() const {
145   return powered_;
148 void BluetoothAdapterMac::SetPowered(bool powered,
149                                      const base::Closure& callback,
150                                      const ErrorCallback& error_callback) {
151   NOTIMPLEMENTED();
154 bool BluetoothAdapterMac::IsDiscoverable() const {
155   NOTIMPLEMENTED();
156   return false;
159 void BluetoothAdapterMac::SetDiscoverable(
160     bool discoverable,
161     const base::Closure& callback,
162     const ErrorCallback& error_callback) {
163   NOTIMPLEMENTED();
166 bool BluetoothAdapterMac::IsDiscovering() const {
167   return discovery_status_ == DISCOVERING ||
168       discovery_status_ == DISCOVERY_STOPPING;
171 void BluetoothAdapterMac::ReadLocalOutOfBandPairingData(
172     const BluetoothOutOfBandPairingDataCallback& callback,
173     const ErrorCallback& error_callback) {
176 void BluetoothAdapterMac::AddDiscoverySession(
177     const base::Closure& callback,
178     const ErrorCallback& error_callback) {
179   if (discovery_status_ == DISCOVERING) {
180     num_discovery_listeners_++;
181     callback.Run();
182     return;
183   }
184   on_start_discovery_callbacks_.push_back(
185       std::make_pair(callback, error_callback));
186   MaybeStartDeviceInquiry();
189 void BluetoothAdapterMac::RemoveDiscoverySession(
190     const base::Closure& callback,
191     const ErrorCallback& error_callback) {
192   if (discovery_status_ == NOT_DISCOVERING) {
193     error_callback.Run();
194     return;
195   }
196   on_stop_discovery_callbacks_.push_back(
197       std::make_pair(callback, error_callback));
198   MaybeStopDeviceInquiry();
201 void BluetoothAdapterMac::RemovePairingDelegateInternal(
202     BluetoothDevice::PairingDelegate* pairing_delegate) {
205 void BluetoothAdapterMac::Init() {
206   ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
207   PollAdapter();
210 void BluetoothAdapterMac::InitForTest(
211     scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
212   ui_task_runner_ = ui_task_runner;
213   PollAdapter();
216 void BluetoothAdapterMac::PollAdapter() {
217   bool was_present = IsPresent();
218   std::string name = "";
219   std::string address = "";
220   bool powered = false;
221   IOBluetoothHostController* controller =
222       [IOBluetoothHostController defaultController];
224   if (controller != nil) {
225     name = base::SysNSStringToUTF8([controller nameAsString]);
226     address = base::SysNSStringToUTF8([controller addressAsString]);
227     powered = ([controller powerState] == kBluetoothHCIPowerStateON);
228   }
230   bool is_present = !address.empty();
231   name_ = name;
232   address_ = address;
234   if (was_present != is_present) {
235     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
236                       AdapterPresentChanged(this, is_present));
237   }
238   if (powered_ != powered) {
239     powered_ = powered;
240     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
241                       AdapterPoweredChanged(this, powered_));
242   }
244   IOBluetoothDevice* recent_device =
245       [[IOBluetoothDevice recentDevices:1] lastObject];
246   NSDate* access_timestamp = [recent_device recentAccessDate];
247   if (recently_accessed_device_timestamp_ == nil ||
248       access_timestamp == nil ||
249       [recently_accessed_device_timestamp_ compare:access_timestamp] ==
250           NSOrderedAscending) {
251     UpdateDevices([IOBluetoothDevice pairedDevices]);
252     [recently_accessed_device_timestamp_ release];
253     recently_accessed_device_timestamp_ = [access_timestamp copy];
254   }
256   ui_task_runner_->PostDelayedTask(
257       FROM_HERE,
258       base::Bind(&BluetoothAdapterMac::PollAdapter,
259                  weak_ptr_factory_.GetWeakPtr()),
260       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
263 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
264   STLDeleteValues(&devices_);
265   for (IOBluetoothDevice* device in devices) {
266     std::string device_address =
267         base::SysNSStringToUTF8([device addressString]);
268     devices_[device_address] = new BluetoothDeviceMac(device);
269   }
272 void BluetoothAdapterMac::DeviceInquiryStarted(
273     IOBluetoothDeviceInquiry* inquiry) {
274   DCHECK(device_inquiry_ == inquiry);
275   if (discovery_status_ == DISCOVERING)
276     return;
278   discovery_status_ = DISCOVERING;
279   RunCallbacks(on_start_discovery_callbacks_, true);
280   num_discovery_listeners_ = on_start_discovery_callbacks_.size();
281   on_start_discovery_callbacks_.clear();
283   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
284                     AdapterDiscoveringChanged(this, true));
285   MaybeStopDeviceInquiry();
288 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry,
289                                       IOBluetoothDevice* device) {
290   DCHECK(device_inquiry_ == inquiry);
291   std::string device_address = base::SysNSStringToUTF8([device addressString]);
292   if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
293     scoped_ptr<BluetoothDeviceMac> device_mac(new BluetoothDeviceMac(device));
294     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
295                       DeviceAdded(this, device_mac.get()));
296     discovered_devices_.insert(device_address);
297   }
300 void BluetoothAdapterMac::DeviceInquiryComplete(
301     IOBluetoothDeviceInquiry* inquiry,
302     IOReturn error,
303     bool aborted) {
304   DCHECK(device_inquiry_ == inquiry);
305   if (discovery_status_ == DISCOVERING &&
306       [device_inquiry_ start] == kIOReturnSuccess) {
307     return;
308   }
310   // Device discovery is done.
311   discovered_devices_.clear();
312   discovery_status_ = NOT_DISCOVERING;
313   RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess);
314   num_discovery_listeners_ = 0;
315   on_stop_discovery_callbacks_.clear();
316   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
317                     AdapterDiscoveringChanged(this, false));
318   MaybeStartDeviceInquiry();
321 void BluetoothAdapterMac::MaybeStartDeviceInquiry() {
322   if (discovery_status_ == NOT_DISCOVERING &&
323       !on_start_discovery_callbacks_.empty()) {
324     discovery_status_ = DISCOVERY_STARTING;
325     if ([device_inquiry_ start] != kIOReturnSuccess) {
326       discovery_status_ = NOT_DISCOVERING;
327       RunCallbacks(on_start_discovery_callbacks_, false);
328       on_start_discovery_callbacks_.clear();
329     }
330   }
333 void BluetoothAdapterMac::MaybeStopDeviceInquiry() {
334   if (discovery_status_ != DISCOVERING)
335     return;
337   if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) {
338     RunCallbacks(on_stop_discovery_callbacks_, true);
339     num_discovery_listeners_ -= on_stop_discovery_callbacks_.size();
340     on_stop_discovery_callbacks_.clear();
341     return;
342   }
344   discovery_status_ = DISCOVERY_STOPPING;
345   if ([device_inquiry_ stop] != kIOReturnSuccess) {
346     RunCallbacks(on_stop_discovery_callbacks_, false);
347     on_stop_discovery_callbacks_.clear();
348   }
351 void BluetoothAdapterMac::RunCallbacks(
352     const DiscoveryCallbackList& callback_list, bool success) const {
353   for (DiscoveryCallbackList::const_iterator iter = callback_list.begin();
354        iter != callback_list.end();
355        ++iter) {
356     if (success)
357       ui_task_runner_->PostTask(FROM_HERE, iter->first);
358     else
359       ui_task_runner_->PostTask(FROM_HERE, iter->second);
360   }
363 }  // namespace device