linux_aura: Disable the plugin install infobar.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_mac.mm
blob6fb2b44e6cc072fb0ad8fe01bf0dd41ee29f1d73
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::CreateRfcommService(
179     const BluetoothUUID& uuid,
180     int channel,
181     bool insecure,
182     const CreateServiceCallback& callback,
183     const CreateServiceErrorCallback& error_callback) {
184   // TODO(keybuk): implement.
185   NOTIMPLEMENTED();
188 void BluetoothAdapterMac::CreateL2capService(
189     const BluetoothUUID& uuid,
190     int psm,
191     const CreateServiceCallback& callback,
192     const CreateServiceErrorCallback& error_callback) {
193   // TODO(keybuk): implement.
194   NOTIMPLEMENTED();
197 void BluetoothAdapterMac::AddDiscoverySession(
198     const base::Closure& callback,
199     const ErrorCallback& error_callback) {
200   if (discovery_status_ == DISCOVERING) {
201     num_discovery_listeners_++;
202     callback.Run();
203     return;
204   }
205   on_start_discovery_callbacks_.push_back(
206       std::make_pair(callback, error_callback));
207   MaybeStartDeviceInquiry();
210 void BluetoothAdapterMac::RemoveDiscoverySession(
211     const base::Closure& callback,
212     const ErrorCallback& error_callback) {
213   if (discovery_status_ == NOT_DISCOVERING) {
214     error_callback.Run();
215     return;
216   }
217   on_stop_discovery_callbacks_.push_back(
218       std::make_pair(callback, error_callback));
219   MaybeStopDeviceInquiry();
222 void BluetoothAdapterMac::RemovePairingDelegateInternal(
223     BluetoothDevice::PairingDelegate* pairing_delegate) {
226 void BluetoothAdapterMac::Init() {
227   ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
228   PollAdapter();
231 void BluetoothAdapterMac::InitForTest(
232     scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
233   ui_task_runner_ = ui_task_runner;
234   PollAdapter();
237 void BluetoothAdapterMac::PollAdapter() {
238   bool was_present = IsPresent();
239   std::string name;
240   std::string address;
241   bool powered = false;
242   IOBluetoothHostController* controller =
243       [IOBluetoothHostController defaultController];
245   if (controller != nil) {
246     name = base::SysNSStringToUTF8([controller nameAsString]);
247     address = BluetoothDevice::CanonicalizeAddress(
248         base::SysNSStringToUTF8([controller addressAsString]));
249     powered = ([controller powerState] == kBluetoothHCIPowerStateON);
250   }
252   bool is_present = !address.empty();
253   name_ = name;
254   address_ = address;
256   if (was_present != is_present) {
257     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
258                       AdapterPresentChanged(this, is_present));
259   }
260   if (powered_ != powered) {
261     powered_ = powered;
262     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
263                       AdapterPoweredChanged(this, powered_));
264   }
266   IOBluetoothDevice* recent_device =
267       [[IOBluetoothDevice recentDevices:1] lastObject];
268   NSDate* access_timestamp = [recent_device recentAccessDate];
269   if (recently_accessed_device_timestamp_ == nil ||
270       access_timestamp == nil ||
271       [recently_accessed_device_timestamp_ compare:access_timestamp] ==
272           NSOrderedAscending) {
273     UpdateDevices([IOBluetoothDevice pairedDevices]);
274     recently_accessed_device_timestamp_.reset([access_timestamp copy]);
275   }
277   ui_task_runner_->PostDelayedTask(
278       FROM_HERE,
279       base::Bind(&BluetoothAdapterMac::PollAdapter,
280                  weak_ptr_factory_.GetWeakPtr()),
281       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
284 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
285   STLDeleteValues(&devices_);
286   for (IOBluetoothDevice* device in devices) {
287     std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
288     devices_[device_address] = new BluetoothDeviceMac(device);
289   }
292 void BluetoothAdapterMac::DeviceInquiryStarted(
293     IOBluetoothDeviceInquiry* inquiry) {
294   DCHECK_EQ(device_inquiry_, inquiry);
295   if (discovery_status_ == DISCOVERING)
296     return;
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();
303   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
304                     AdapterDiscoveringChanged(this, true));
305   MaybeStopDeviceInquiry();
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   }
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   }
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();
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   }
353 void BluetoothAdapterMac::MaybeStopDeviceInquiry() {
354   if (discovery_status_ != DISCOVERING)
355     return;
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   }
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   }
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   }
383 }  // namespace device