Turning in DCHECK to test for illegal visibility / opacity flag combination
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_mac.mm
blobcf899cbc0783bb33eca9634913803f41ee778766
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"
24 #include "device/bluetooth/bluetooth_socket_mac.h"
25 #include "device/bluetooth/bluetooth_uuid.h"
27 // Replicate specific 10.7 SDK declarations for building with prior SDKs.
28 #if !defined(MAC_OS_X_VERSION_10_7) || \
29 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
31 @interface IOBluetoothHostController (LionSDKDeclarations)
32 - (NSString*)nameAsString;
33 - (BluetoothHCIPowerState)powerState;
34 @end
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
45 #endif  // MAC_OS_X_VERSION_10_7
47 @interface BluetoothAdapterMacDelegate
48     : NSObject <IOBluetoothDeviceInquiryDelegate> {
49  @private
50   device::BluetoothAdapterMac* adapter_;  // weak
53 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter;
55 @end
57 @implementation BluetoothAdapterMacDelegate
59 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter {
60   if ((self = [super init]))
61     adapter_ = adapter;
63   return self;
66 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender {
67   adapter_->DeviceInquiryStarted(sender);
70 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
71                           device:(IOBluetoothDevice*)device {
72   adapter_->DeviceFound(sender, device);
75 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
76                         error:(IOReturn)error
77                       aborted:(BOOL)aborted {
78   adapter_->DeviceInquiryComplete(sender, error, aborted);
81 @end
83 namespace {
85 const int kPollIntervalMs = 500;
87 }  // namespace
89 namespace device {
91 // static
92 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
93     const InitCallback& init_callback) {
94   return BluetoothAdapterMac::CreateAdapter();
97 // static
98 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() {
99   BluetoothAdapterMac* adapter = new BluetoothAdapterMac();
100   adapter->Init();
101   return adapter->weak_ptr_factory_.GetWeakPtr();
104 BluetoothAdapterMac::BluetoothAdapterMac()
105     : BluetoothAdapter(),
106       powered_(false),
107       discovery_status_(NOT_DISCOVERING),
108       adapter_delegate_(
109           [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]),
110       device_inquiry_(
111           [[IOBluetoothDeviceInquiry
112               inquiryWithDelegate:adapter_delegate_] retain]),
113       weak_ptr_factory_(this) {
116 BluetoothAdapterMac::~BluetoothAdapterMac() {
119 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) {
120   DCHECK(observer);
121   observers_.AddObserver(observer);
124 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) {
125   DCHECK(observer);
126   observers_.RemoveObserver(observer);
129 std::string BluetoothAdapterMac::GetAddress() const {
130   return address_;
133 std::string BluetoothAdapterMac::GetName() const {
134   return name_;
137 void BluetoothAdapterMac::SetName(const std::string& name,
138                                   const base::Closure& callback,
139                                   const ErrorCallback& error_callback) {
140   NOTIMPLEMENTED();
143 bool BluetoothAdapterMac::IsInitialized() const {
144   return true;
147 bool BluetoothAdapterMac::IsPresent() const {
148   return !address_.empty();
151 bool BluetoothAdapterMac::IsPowered() const {
152   return powered_;
155 void BluetoothAdapterMac::SetPowered(bool powered,
156                                      const base::Closure& callback,
157                                      const ErrorCallback& error_callback) {
158   NOTIMPLEMENTED();
161 bool BluetoothAdapterMac::IsDiscoverable() const {
162   NOTIMPLEMENTED();
163   return false;
166 void BluetoothAdapterMac::SetDiscoverable(
167     bool discoverable,
168     const base::Closure& callback,
169     const ErrorCallback& error_callback) {
170   NOTIMPLEMENTED();
173 bool BluetoothAdapterMac::IsDiscovering() const {
174   return discovery_status_ == DISCOVERING ||
175       discovery_status_ == DISCOVERY_STOPPING;
178 void BluetoothAdapterMac::ReadLocalOutOfBandPairingData(
179     const BluetoothOutOfBandPairingDataCallback& callback,
180     const ErrorCallback& error_callback) {
183 void BluetoothAdapterMac::CreateRfcommService(
184     const BluetoothUUID& uuid,
185     int channel,
186     bool insecure,
187     const CreateServiceCallback& callback,
188     const CreateServiceErrorCallback& error_callback) {
189   // TODO(keybuk): implement.
190   NOTIMPLEMENTED();
193 void BluetoothAdapterMac::CreateL2capService(
194     const BluetoothUUID& uuid,
195     int psm,
196     const CreateServiceCallback& callback,
197     const CreateServiceErrorCallback& error_callback) {
198   // TODO(keybuk): implement.
199   NOTIMPLEMENTED();
202 void BluetoothAdapterMac::AddDiscoverySession(
203     const base::Closure& callback,
204     const ErrorCallback& error_callback) {
205   if (discovery_status_ == DISCOVERING) {
206     num_discovery_listeners_++;
207     callback.Run();
208     return;
209   }
210   on_start_discovery_callbacks_.push_back(
211       std::make_pair(callback, error_callback));
212   MaybeStartDeviceInquiry();
215 void BluetoothAdapterMac::RemoveDiscoverySession(
216     const base::Closure& callback,
217     const ErrorCallback& error_callback) {
218   if (discovery_status_ == NOT_DISCOVERING) {
219     error_callback.Run();
220     return;
221   }
222   on_stop_discovery_callbacks_.push_back(
223       std::make_pair(callback, error_callback));
224   MaybeStopDeviceInquiry();
227 void BluetoothAdapterMac::RemovePairingDelegateInternal(
228     BluetoothDevice::PairingDelegate* pairing_delegate) {
231 void BluetoothAdapterMac::Init() {
232   ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
233   PollAdapter();
236 void BluetoothAdapterMac::InitForTest(
237     scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
238   ui_task_runner_ = ui_task_runner;
239   PollAdapter();
242 void BluetoothAdapterMac::PollAdapter() {
243   bool was_present = IsPresent();
244   std::string name;
245   std::string address;
246   bool powered = false;
247   IOBluetoothHostController* controller =
248       [IOBluetoothHostController defaultController];
250   if (controller != nil) {
251     name = base::SysNSStringToUTF8([controller nameAsString]);
252     address = BluetoothDeviceMac::NormalizeAddress(
253         base::SysNSStringToUTF8([controller addressAsString]));
254     powered = ([controller powerState] == kBluetoothHCIPowerStateON);
255   }
257   bool is_present = !address.empty();
258   name_ = name;
259   address_ = address;
261   if (was_present != is_present) {
262     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
263                       AdapterPresentChanged(this, is_present));
264   }
265   if (powered_ != powered) {
266     powered_ = powered;
267     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
268                       AdapterPoweredChanged(this, powered_));
269   }
271   IOBluetoothDevice* recent_device =
272       [[IOBluetoothDevice recentDevices:1] lastObject];
273   NSDate* access_timestamp = [recent_device recentAccessDate];
274   if (recently_accessed_device_timestamp_ == nil ||
275       access_timestamp == nil ||
276       [recently_accessed_device_timestamp_ compare:access_timestamp] ==
277           NSOrderedAscending) {
278     UpdateDevices([IOBluetoothDevice pairedDevices]);
279     recently_accessed_device_timestamp_.reset([access_timestamp copy]);
280   }
282   ui_task_runner_->PostDelayedTask(
283       FROM_HERE,
284       base::Bind(&BluetoothAdapterMac::PollAdapter,
285                  weak_ptr_factory_.GetWeakPtr()),
286       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
289 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
290   STLDeleteValues(&devices_);
291   for (IOBluetoothDevice* device in devices) {
292     std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
293     devices_[device_address] = new BluetoothDeviceMac(device);
294   }
297 void BluetoothAdapterMac::DeviceInquiryStarted(
298     IOBluetoothDeviceInquiry* inquiry) {
299   DCHECK_EQ(device_inquiry_, inquiry);
300   if (discovery_status_ == DISCOVERING)
301     return;
303   discovery_status_ = DISCOVERING;
304   RunCallbacks(on_start_discovery_callbacks_, true);
305   num_discovery_listeners_ = on_start_discovery_callbacks_.size();
306   on_start_discovery_callbacks_.clear();
308   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
309                     AdapterDiscoveringChanged(this, true));
310   MaybeStopDeviceInquiry();
313 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry,
314                                       IOBluetoothDevice* device) {
315   DCHECK_EQ(device_inquiry_, inquiry);
316   std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
317   if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
318     BluetoothDeviceMac device_mac(device);
319     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
320                       DeviceAdded(this, &device_mac));
321     discovered_devices_.insert(device_address);
322   }
325 void BluetoothAdapterMac::DeviceInquiryComplete(
326     IOBluetoothDeviceInquiry* inquiry,
327     IOReturn error,
328     bool aborted) {
329   DCHECK_EQ(device_inquiry_, inquiry);
330   if (discovery_status_ == DISCOVERING &&
331       [device_inquiry_ start] == kIOReturnSuccess) {
332     return;
333   }
335   // Device discovery is done.
336   discovered_devices_.clear();
337   discovery_status_ = NOT_DISCOVERING;
338   RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess);
339   num_discovery_listeners_ = 0;
340   on_stop_discovery_callbacks_.clear();
341   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
342                     AdapterDiscoveringChanged(this, false));
343   MaybeStartDeviceInquiry();
346 void BluetoothAdapterMac::MaybeStartDeviceInquiry() {
347   if (discovery_status_ == NOT_DISCOVERING &&
348       !on_start_discovery_callbacks_.empty()) {
349     discovery_status_ = DISCOVERY_STARTING;
350     if ([device_inquiry_ start] != kIOReturnSuccess) {
351       discovery_status_ = NOT_DISCOVERING;
352       RunCallbacks(on_start_discovery_callbacks_, false);
353       on_start_discovery_callbacks_.clear();
354     }
355   }
358 void BluetoothAdapterMac::MaybeStopDeviceInquiry() {
359   if (discovery_status_ != DISCOVERING)
360     return;
362   if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) {
363     RunCallbacks(on_stop_discovery_callbacks_, true);
364     num_discovery_listeners_ -= on_stop_discovery_callbacks_.size();
365     on_stop_discovery_callbacks_.clear();
366     return;
367   }
369   discovery_status_ = DISCOVERY_STOPPING;
370   if ([device_inquiry_ stop] != kIOReturnSuccess) {
371     RunCallbacks(on_stop_discovery_callbacks_, false);
372     on_stop_discovery_callbacks_.clear();
373   }
376 void BluetoothAdapterMac::RunCallbacks(
377     const DiscoveryCallbackList& callback_list, bool success) const {
378   for (DiscoveryCallbackList::const_iterator iter = callback_list.begin();
379        iter != callback_list.end();
380        ++iter) {
381     if (success)
382       ui_task_runner_->PostTask(FROM_HERE, iter->first);
383     else
384       ui_task_runner_->PostTask(FROM_HERE, iter->second);
385   }
388 }  // namespace device