Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_mac.mm
bloba528bd7229bee3d5f7a8b037c38614d050f336af
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/IOBluetoothHostController.h>
10 #include <string>
12 #include "base/bind.h"
13 #include "base/compiler_specific.h"
14 #include "base/containers/hash_tables.h"
15 #include "base/location.h"
16 #include "base/mac/sdk_forward_declarations.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/profiler/scoped_tracker.h"
19 #include "base/sequenced_task_runner.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/strings/sys_string_conversions.h"
22 #include "base/thread_task_runner_handle.h"
23 #include "base/time/time.h"
24 #include "device/bluetooth/bluetooth_device_mac.h"
25 #include "device/bluetooth/bluetooth_socket_mac.h"
26 #include "device/bluetooth/bluetooth_uuid.h"
28 namespace {
30 // The frequency with which to poll the adapter for updates.
31 const int kPollIntervalMs = 500;
33 // The length of time that must elapse since the last Inquiry response before a
34 // discovered Classic device is considered to be no longer available.
35 const NSTimeInterval kDiscoveryTimeoutSec = 3 * 60;  // 3 minutes
37 }  // namespace
39 namespace device {
41 // static
42 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
43     const InitCallback& init_callback) {
44   return BluetoothAdapterMac::CreateAdapter();
47 // static
48 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() {
49   BluetoothAdapterMac* adapter = new BluetoothAdapterMac();
50   adapter->Init();
51   return adapter->weak_ptr_factory_.GetWeakPtr();
54 BluetoothAdapterMac::BluetoothAdapterMac()
55     : BluetoothAdapter(),
56       powered_(false),
57       num_discovery_sessions_(0),
58       classic_discovery_manager_(
59           BluetoothDiscoveryManagerMac::CreateClassic(this)),
60       weak_ptr_factory_(this) {
61   DCHECK(classic_discovery_manager_.get());
64 BluetoothAdapterMac::~BluetoothAdapterMac() {
67 std::string BluetoothAdapterMac::GetAddress() const {
68   return address_;
71 std::string BluetoothAdapterMac::GetName() const {
72   return name_;
75 void BluetoothAdapterMac::SetName(const std::string& name,
76                                   const base::Closure& callback,
77                                   const ErrorCallback& error_callback) {
78   NOTIMPLEMENTED();
81 bool BluetoothAdapterMac::IsInitialized() const {
82   return true;
85 bool BluetoothAdapterMac::IsPresent() const {
86   return !address_.empty();
89 bool BluetoothAdapterMac::IsPowered() const {
90   return powered_;
93 void BluetoothAdapterMac::SetPowered(bool powered,
94                                      const base::Closure& callback,
95                                      const ErrorCallback& error_callback) {
96   NOTIMPLEMENTED();
99 bool BluetoothAdapterMac::IsDiscoverable() const {
100   NOTIMPLEMENTED();
101   return false;
104 void BluetoothAdapterMac::SetDiscoverable(
105     bool discoverable,
106     const base::Closure& callback,
107     const ErrorCallback& error_callback) {
108   NOTIMPLEMENTED();
111 bool BluetoothAdapterMac::IsDiscovering() const {
112   return classic_discovery_manager_->IsDiscovering();
115 void BluetoothAdapterMac::CreateRfcommService(
116     const BluetoothUUID& uuid,
117     const ServiceOptions& options,
118     const CreateServiceCallback& callback,
119     const CreateServiceErrorCallback& error_callback) {
120   scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
121   socket->ListenUsingRfcomm(
122       this, uuid, options, base::Bind(callback, socket), error_callback);
125 void BluetoothAdapterMac::CreateL2capService(
126     const BluetoothUUID& uuid,
127     const ServiceOptions& options,
128     const CreateServiceCallback& callback,
129     const CreateServiceErrorCallback& error_callback) {
130   scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
131   socket->ListenUsingL2cap(
132       this, uuid, options, base::Bind(callback, socket), error_callback);
135 void BluetoothAdapterMac::RegisterAudioSink(
136     const BluetoothAudioSink::Options& options,
137     const AcquiredCallback& callback,
138     const BluetoothAudioSink::ErrorCallback& error_callback) {
139   NOTIMPLEMENTED();
140   error_callback.Run(BluetoothAudioSink::ERROR_UNSUPPORTED_PLATFORM);
143 void BluetoothAdapterMac::DeviceFound(IOBluetoothDevice* device) {
144   DeviceAdded(device);
147 void BluetoothAdapterMac::DiscoveryStopped(bool unexpected) {
148   if (unexpected) {
149     DVLOG(1) << "Discovery stopped unexpectedly";
150     num_discovery_sessions_ = 0;
151     MarkDiscoverySessionsAsInactive();
152   }
153   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
154                     observers_,
155                     AdapterDiscoveringChanged(this, false));
158 void BluetoothAdapterMac::DeviceConnected(IOBluetoothDevice* device) {
159   // TODO(isherman): Investigate whether this method can be replaced with a call
160   // to +registerForConnectNotifications:selector:.
161   DVLOG(1) << "Adapter registered a new connection from device with address: "
162            << BluetoothDeviceMac::GetDeviceAddress(device);
163   DeviceAdded(device);
166 void BluetoothAdapterMac::AddDiscoverySession(
167     BluetoothDiscoveryFilter* discovery_filter,
168     const base::Closure& callback,
169     const ErrorCallback& error_callback) {
170   DVLOG(1) << __func__;
171   if (num_discovery_sessions_ > 0) {
172     DCHECK(IsDiscovering());
173     num_discovery_sessions_++;
174     callback.Run();
175     return;
176   }
178   DCHECK_EQ(0, num_discovery_sessions_);
180   if (!classic_discovery_manager_->StartDiscovery()) {
181     DVLOG(1) << "Failed to add a discovery session";
182     error_callback.Run();
183     return;
184   }
186   DVLOG(1) << "Added a discovery session";
187   num_discovery_sessions_++;
188   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
189                     observers_,
190                     AdapterDiscoveringChanged(this, true));
191   callback.Run();
194 void BluetoothAdapterMac::RemoveDiscoverySession(
195     BluetoothDiscoveryFilter* discovery_filter,
196     const base::Closure& callback,
197     const ErrorCallback& error_callback) {
198   DVLOG(1) << __func__;
200   if (num_discovery_sessions_ > 1) {
201     // There are active sessions other than the one currently being removed.
202     DCHECK(IsDiscovering());
203     num_discovery_sessions_--;
204     callback.Run();
205     return;
206   }
208   if (num_discovery_sessions_ == 0) {
209     DVLOG(1) << "No active discovery sessions. Returning error.";
210     error_callback.Run();
211     return;
212   }
214   if (!classic_discovery_manager_->StopDiscovery()) {
215     DVLOG(1) << "Failed to stop discovery";
216     error_callback.Run();
217     return;
218   }
220   DVLOG(1) << "Discovery stopped";
221   num_discovery_sessions_--;
222   callback.Run();
225 void BluetoothAdapterMac::SetDiscoveryFilter(
226     scoped_ptr<BluetoothDiscoveryFilter> discovery_filter,
227     const base::Closure& callback,
228     const ErrorCallback& error_callback) {
229   NOTIMPLEMENTED();
230   error_callback.Run();
233 void BluetoothAdapterMac::RemovePairingDelegateInternal(
234     BluetoothDevice::PairingDelegate* pairing_delegate) {
237 void BluetoothAdapterMac::Init() {
238   ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
239   PollAdapter();
242 void BluetoothAdapterMac::InitForTest(
243     scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
244   ui_task_runner_ = ui_task_runner;
245   PollAdapter();
248 void BluetoothAdapterMac::PollAdapter() {
249   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461181
250   // is fixed.
251   tracked_objects::ScopedTracker tracking_profile1(
252       FROM_HERE_WITH_EXPLICIT_FUNCTION(
253           "461181 BluetoothAdapterMac::PollAdapter::Start"));
254   bool was_present = IsPresent();
255   std::string name;
256   std::string address;
257   bool powered = false;
258   IOBluetoothHostController* controller =
259       [IOBluetoothHostController defaultController];
261   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461181
262   // is fixed.
263   tracked_objects::ScopedTracker tracking_profile2(
264       FROM_HERE_WITH_EXPLICIT_FUNCTION(
265           "461181 BluetoothAdapterMac::PollAdapter::GetControllerStats"));
266   if (controller != nil) {
267     name = base::SysNSStringToUTF8([controller nameAsString]);
268     address = BluetoothDevice::CanonicalizeAddress(
269         base::SysNSStringToUTF8([controller addressAsString]));
270     powered = ([controller powerState] == kBluetoothHCIPowerStateON);
271   }
273   bool is_present = !address.empty();
274   name_ = name;
275   address_ = address;
277   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461181
278   // is fixed.
279   tracked_objects::ScopedTracker tracking_profile3(
280       FROM_HERE_WITH_EXPLICIT_FUNCTION(
281           "461181 BluetoothAdapterMac::PollAdapter::AdapterPresentChanged"));
282   if (was_present != is_present) {
283     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
284                       AdapterPresentChanged(this, is_present));
285   }
287   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461181
288   // is fixed.
289   tracked_objects::ScopedTracker tracking_profile4(
290       FROM_HERE_WITH_EXPLICIT_FUNCTION(
291           "461181 BluetoothAdapterMac::PollAdapter::AdapterPowerChanged"));
292   if (powered_ != powered) {
293     powered_ = powered;
294     FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
295                       AdapterPoweredChanged(this, powered_));
296   }
298   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461181
299   // is fixed.
300   tracked_objects::ScopedTracker tracking_profile5(
301       FROM_HERE_WITH_EXPLICIT_FUNCTION(
302           "461181 BluetoothAdapterMac::PollAdapter::UpdateDevices"));
303   UpdateDevices();
305   ui_task_runner_->PostDelayedTask(
306       FROM_HERE,
307       base::Bind(&BluetoothAdapterMac::PollAdapter,
308                  weak_ptr_factory_.GetWeakPtr()),
309       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
312 void BluetoothAdapterMac::DeviceAdded(IOBluetoothDevice* device) {
313   std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
315   // Only notify observers once per device.
316   if (devices_.count(device_address))
317     return;
319   devices_[device_address] = new BluetoothDeviceMac(device);
320   FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
321                     observers_,
322                     DeviceAdded(this, devices_[device_address]));
325 void BluetoothAdapterMac::UpdateDevices() {
326   // Notify observers if any previously seen devices are no longer available,
327   // i.e. if they are no longer paired, connected, nor recently discovered via
328   // an inquiry.
329   std::set<std::string> removed_devices;
330   for (DevicesMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
331     BluetoothDevice* device = it->second;
332     if (device->IsPaired() || device->IsConnected())
333       continue;
335     NSDate* last_inquiry_update =
336         static_cast<BluetoothDeviceMac*>(device)->GetLastInquiryUpdate();
337     if (last_inquiry_update &&
338         -[last_inquiry_update timeIntervalSinceNow] < kDiscoveryTimeoutSec)
339       continue;
341     FOR_EACH_OBSERVER(
342         BluetoothAdapter::Observer, observers_, DeviceRemoved(this, device));
343     delete device;
344     removed_devices.insert(it->first);
345     // The device will be erased from the map in the loop immediately below.
346   }
347   for (const std::string& device_address : removed_devices) {
348     size_t num_removed = devices_.erase(device_address);
349     DCHECK_EQ(num_removed, 1U);
350   }
352   // Add any new paired devices.
353   for (IOBluetoothDevice* device in [IOBluetoothDevice pairedDevices]) {
354     DeviceAdded(device);
355   }
358 }  // namespace device