Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / device / bluetooth / bluetooth_adapter_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_adapter_mac.h"
6
7 #import <IOBluetooth/objc/IOBluetoothDevice.h>
8 #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
9 #import <IOBluetooth/objc/IOBluetoothHostController.h>
10
11 #include <string>
12
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
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
28
29 @interface IOBluetoothHostController (LionSDKDeclarations)
30 - (NSString*)nameAsString;
31 - (BluetoothHCIPowerState)powerState;
32 @end
33
34 @protocol IOBluetoothDeviceInquiryDelegate
35 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
36 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
37                           device:(IOBluetoothDevice*)device;
38 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
39                         error:(IOReturn)error
40                       aborted:(BOOL)aborted;
41 @end
42
43 #endif  // MAC_OS_X_VERSION_10_7
44
45 @interface BluetoothAdapterMacDelegate
46     : NSObject <IOBluetoothDeviceInquiryDelegate> {
47  @private
48   device::BluetoothAdapterMac* adapter_;  // weak
49 }
50
51 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter;
52
53 @end
54
55 @implementation BluetoothAdapterMacDelegate
56
57 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter {
58   if ((self = [super init]))
59     adapter_ = adapter;
60
61   return self;
62 }
63
64 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender {
65   adapter_->DeviceInquiryStarted(sender);
66 }
67
68 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
69                           device:(IOBluetoothDevice*)device {
70   adapter_->DeviceFound(sender, device);
71 }
72
73 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
74                         error:(IOReturn)error
75                       aborted:(BOOL)aborted {
76   adapter_->DeviceInquiryComplete(sender, error, aborted);
77 }
78
79 @end
80
81 namespace {
82
83 const int kPollIntervalMs = 500;
84
85 }  // namespace
86
87 namespace device {
88
89 // static
90 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
91     const InitCallback& init_callback) {
92   return BluetoothAdapterMac::CreateAdapter();
93 }
94
95 // static
96 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() {
97   BluetoothAdapterMac* adapter = new BluetoothAdapterMac();
98   adapter->Init();
99   return adapter->weak_ptr_factory_.GetWeakPtr();
100 }
101
102 BluetoothAdapterMac::BluetoothAdapterMac()
103     : BluetoothAdapter(),
104       powered_(false),
105       discovery_status_(NOT_DISCOVERING),
106       adapter_delegate_(
107           [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]),
108       device_inquiry_(
109           [[IOBluetoothDeviceInquiry
110               inquiryWithDelegate:adapter_delegate_] retain]),
111       weak_ptr_factory_(this) {
112 }
113
114 BluetoothAdapterMac::~BluetoothAdapterMac() {
115 }
116
117 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) {
118   DCHECK(observer);
119   observers_.AddObserver(observer);
120 }
121
122 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) {
123   DCHECK(observer);
124   observers_.RemoveObserver(observer);
125 }
126
127 std::string BluetoothAdapterMac::GetAddress() const {
128   return address_;
129 }
130
131 std::string BluetoothAdapterMac::GetName() const {
132   return name_;
133 }
134
135 void BluetoothAdapterMac::SetName(const std::string& name,
136                                   const base::Closure& callback,
137                                   const ErrorCallback& error_callback) {
138   NOTIMPLEMENTED();
139 }
140
141 bool BluetoothAdapterMac::IsInitialized() const {
142   return true;
143 }
144
145 bool BluetoothAdapterMac::IsPresent() const {
146   return !address_.empty();
147 }
148
149 bool BluetoothAdapterMac::IsPowered() const {
150   return powered_;
151 }
152
153 void BluetoothAdapterMac::SetPowered(bool powered,
154                                      const base::Closure& callback,
155                                      const ErrorCallback& error_callback) {
156   NOTIMPLEMENTED();
157 }
158
159 bool BluetoothAdapterMac::IsDiscoverable() const {
160   NOTIMPLEMENTED();
161   return false;
162 }
163
164 void BluetoothAdapterMac::SetDiscoverable(
165     bool discoverable,
166     const base::Closure& callback,
167     const ErrorCallback& error_callback) {
168   NOTIMPLEMENTED();
169 }
170
171 bool BluetoothAdapterMac::IsDiscovering() const {
172   return discovery_status_ == DISCOVERING ||
173       discovery_status_ == DISCOVERY_STOPPING;
174 }
175
176 void BluetoothAdapterMac::ReadLocalOutOfBandPairingData(
177     const BluetoothOutOfBandPairingDataCallback& callback,
178     const ErrorCallback& error_callback) {
179 }
180
181 void BluetoothAdapterMac::AddDiscoverySession(
182     const base::Closure& callback,
183     const ErrorCallback& error_callback) {
184   if (discovery_status_ == DISCOVERING) {
185     num_discovery_listeners_++;
186     callback.Run();
187     return;
188   }
189   on_start_discovery_callbacks_.push_back(
190       std::make_pair(callback, error_callback));
191   MaybeStartDeviceInquiry();
192 }
193
194 void BluetoothAdapterMac::RemoveDiscoverySession(
195     const base::Closure& callback,
196     const ErrorCallback& error_callback) {
197   if (discovery_status_ == NOT_DISCOVERING) {
198     error_callback.Run();
199     return;
200   }
201   on_stop_discovery_callbacks_.push_back(
202       std::make_pair(callback, error_callback));
203   MaybeStopDeviceInquiry();
204 }
205
206 void BluetoothAdapterMac::RemovePairingDelegateInternal(
207     BluetoothDevice::PairingDelegate* pairing_delegate) {
208 }
209
210 void BluetoothAdapterMac::Init() {
211   ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
212   PollAdapter();
213 }
214
215 void BluetoothAdapterMac::InitForTest(
216     scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
217   ui_task_runner_ = ui_task_runner;
218   PollAdapter();
219 }
220
221 void BluetoothAdapterMac::PollAdapter() {
222   bool was_present = IsPresent();
223   std::string name;
224   std::string address;
225   bool powered = false;
226   IOBluetoothHostController* controller =
227       [IOBluetoothHostController defaultController];
228
229   if (controller != nil) {
230     name = base::SysNSStringToUTF8([controller nameAsString]);
231     address = BluetoothDeviceMac::NormalizeAddress(
232         base::SysNSStringToUTF8([controller addressAsString]));
233     powered = ([controller powerState] == kBluetoothHCIPowerStateON);
234   }
235
236   bool is_present = !address.empty();
237   name_ = name;
238   address_ = address;
239
240   if (was_present != is_present) {
241     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
242                       AdapterPresentChanged(this, is_present));
243   }
244   if (powered_ != powered) {
245     powered_ = powered;
246     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
247                       AdapterPoweredChanged(this, powered_));
248   }
249
250   IOBluetoothDevice* recent_device =
251       [[IOBluetoothDevice recentDevices:1] lastObject];
252   NSDate* access_timestamp = [recent_device recentAccessDate];
253   if (recently_accessed_device_timestamp_ == nil ||
254       access_timestamp == nil ||
255       [recently_accessed_device_timestamp_ compare:access_timestamp] ==
256           NSOrderedAscending) {
257     UpdateDevices([IOBluetoothDevice pairedDevices]);
258     recently_accessed_device_timestamp_.reset([access_timestamp copy]);
259   }
260
261   ui_task_runner_->PostDelayedTask(
262       FROM_HERE,
263       base::Bind(&BluetoothAdapterMac::PollAdapter,
264                  weak_ptr_factory_.GetWeakPtr()),
265       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
266 }
267
268 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
269   STLDeleteValues(&devices_);
270   for (IOBluetoothDevice* device in devices) {
271     std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
272     devices_[device_address] = new BluetoothDeviceMac(device);
273   }
274 }
275
276 void BluetoothAdapterMac::DeviceInquiryStarted(
277     IOBluetoothDeviceInquiry* inquiry) {
278   DCHECK_EQ(device_inquiry_, inquiry);
279   if (discovery_status_ == DISCOVERING)
280     return;
281
282   discovery_status_ = DISCOVERING;
283   RunCallbacks(on_start_discovery_callbacks_, true);
284   num_discovery_listeners_ = on_start_discovery_callbacks_.size();
285   on_start_discovery_callbacks_.clear();
286
287   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
288                     AdapterDiscoveringChanged(this, true));
289   MaybeStopDeviceInquiry();
290 }
291
292 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry,
293                                       IOBluetoothDevice* device) {
294   DCHECK_EQ(device_inquiry_, inquiry);
295   std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
296   if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
297     BluetoothDeviceMac device_mac(device);
298     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
299                       DeviceAdded(this, &device_mac));
300     discovered_devices_.insert(device_address);
301   }
302 }
303
304 void BluetoothAdapterMac::DeviceInquiryComplete(
305     IOBluetoothDeviceInquiry* inquiry,
306     IOReturn error,
307     bool aborted) {
308   DCHECK_EQ(device_inquiry_, inquiry);
309   if (discovery_status_ == DISCOVERING &&
310       [device_inquiry_ start] == kIOReturnSuccess) {
311     return;
312   }
313
314   // Device discovery is done.
315   discovered_devices_.clear();
316   discovery_status_ = NOT_DISCOVERING;
317   RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess);
318   num_discovery_listeners_ = 0;
319   on_stop_discovery_callbacks_.clear();
320   FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
321                     AdapterDiscoveringChanged(this, false));
322   MaybeStartDeviceInquiry();
323 }
324
325 void BluetoothAdapterMac::MaybeStartDeviceInquiry() {
326   if (discovery_status_ == NOT_DISCOVERING &&
327       !on_start_discovery_callbacks_.empty()) {
328     discovery_status_ = DISCOVERY_STARTING;
329     if ([device_inquiry_ start] != kIOReturnSuccess) {
330       discovery_status_ = NOT_DISCOVERING;
331       RunCallbacks(on_start_discovery_callbacks_, false);
332       on_start_discovery_callbacks_.clear();
333     }
334   }
335 }
336
337 void BluetoothAdapterMac::MaybeStopDeviceInquiry() {
338   if (discovery_status_ != DISCOVERING)
339     return;
340
341   if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) {
342     RunCallbacks(on_stop_discovery_callbacks_, true);
343     num_discovery_listeners_ -= on_stop_discovery_callbacks_.size();
344     on_stop_discovery_callbacks_.clear();
345     return;
346   }
347
348   discovery_status_ = DISCOVERY_STOPPING;
349   if ([device_inquiry_ stop] != kIOReturnSuccess) {
350     RunCallbacks(on_stop_discovery_callbacks_, false);
351     on_stop_discovery_callbacks_.clear();
352   }
353 }
354
355 void BluetoothAdapterMac::RunCallbacks(
356     const DiscoveryCallbackList& callback_list, bool success) const {
357   for (DiscoveryCallbackList::const_iterator iter = callback_list.begin();
358        iter != callback_list.end();
359        ++iter) {
360     if (success)
361       ui_task_runner_->PostTask(FROM_HERE, iter->first);
362     else
363       ui_task_runner_->PostTask(FROM_HERE, iter->second);
364   }
365 }
366
367 }  // namespace device