summaryrefslogtreecommitdiffstats
path: root/device/bluetooth
diff options
context:
space:
mode:
authorarmansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-13 08:37:47 +0000
committerarmansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-13 08:37:47 +0000
commit38e653a53dd9b87ed89595b864e81eb862370456 (patch)
treedebe75f5d78b3ad34a1f4a20b64d8ccdea695ce4 /device/bluetooth
parent86352bfc141d446dc08670ef74f0a315338798dd (diff)
downloadchromium_src-38e653a53dd9b87ed89595b864e81eb862370456.zip
chromium_src-38e653a53dd9b87ed89595b864e81eb862370456.tar.gz
chromium_src-38e653a53dd9b87ed89595b864e81eb862370456.tar.bz2
device/bluetooth: Clean up classic discovery in BluetoothAdapterMac.
This CL cleans up the way the IOBluetoothDeviceInquiry object's state and the callbacks passed to AddDiscoverySession and RemoveDiscoverySession are managed by BluetoothAdapterMac. Since the API functions start and stop already report their result synchronously, success/failure can be determined without complex tracking of delegate methods. This CL moves the explicit restarting of inquiry sessions into separate class and makes AddDiscoverySession and RemoveDiscoverySession behave in a way that is consistent with the overall DiscoverySession API. BUG=381980,345007 TEST=Tested several parallel discovery sessions on a MacBook Pro with OS 10.9.2 Review URL: https://codereview.chromium.org/319183010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276973 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/bluetooth')
-rw-r--r--device/bluetooth/bluetooth.gyp2
-rw-r--r--device/bluetooth/bluetooth_adapter_mac.h42
-rw-r--r--device/bluetooth/bluetooth_adapter_mac.mm219
-rw-r--r--device/bluetooth/bluetooth_discovery_manager_mac.h66
-rw-r--r--device/bluetooth/bluetooth_discovery_manager_mac.mm222
5 files changed, 375 insertions, 176 deletions
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index 9ad8f32c..350dfe0 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -51,6 +51,8 @@
'bluetooth_gatt_service.h',
'bluetooth_init_win.cc',
'bluetooth_init_win.h',
+ 'bluetooth_discovery_manager_mac.mm',
+ 'bluetooth_discovery_manager_mac.h',
'bluetooth_pairing_chromeos.cc',
'bluetooth_pairing_chromeos.h',
'bluetooth_remote_gatt_characteristic_chromeos.cc',
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h
index 1d65f68..02a6e8a 100644
--- a/device/bluetooth/bluetooth_adapter_mac.h
+++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -16,10 +16,9 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_discovery_manager_mac.h"
-@class BluetoothAdapterMacDelegate;
@class IOBluetoothDevice;
-@class IOBluetoothDeviceInquiry;
@class NSArray;
@class NSDate;
@@ -33,7 +32,8 @@ namespace device {
class BluetoothAdapterMacTest;
-class BluetoothAdapterMac : public BluetoothAdapter {
+class BluetoothAdapterMac : public BluetoothAdapter,
+ public BluetoothDiscoveryManagerMac::Observer {
public:
static base::WeakPtr<BluetoothAdapter> CreateAdapter();
@@ -69,13 +69,11 @@ class BluetoothAdapterMac : public BluetoothAdapter {
const CreateServiceCallback& callback,
const CreateServiceErrorCallback& error_callback) OVERRIDE;
- // called by BluetoothAdapterMacDelegate.
- void DeviceInquiryStarted(IOBluetoothDeviceInquiry* inquiry);
- void DeviceFound(IOBluetoothDeviceInquiry* inquiry,
- IOBluetoothDevice* device);
- void DeviceInquiryComplete(IOBluetoothDeviceInquiry* inquiry,
- IOReturn error,
- bool aborted);
+ // BluetoothDiscoveryManagerMac::Observer overrides
+ virtual void DeviceFound(BluetoothDiscoveryManagerMac* manager,
+ IOBluetoothDevice* device) OVERRIDE;
+ virtual void DiscoveryStopped(BluetoothDiscoveryManagerMac* manager,
+ bool unexpected) OVERRIDE;
protected:
// BluetoothAdapter:
@@ -85,13 +83,6 @@ class BluetoothAdapterMac : public BluetoothAdapter {
private:
friend class BluetoothAdapterMacTest;
- enum DiscoveryStatus {
- NOT_DISCOVERING,
- DISCOVERY_STARTING,
- DISCOVERING,
- DISCOVERY_STOPPING
- };
-
BluetoothAdapterMac();
virtual ~BluetoothAdapterMac();
@@ -110,25 +101,14 @@ class BluetoothAdapterMac : public BluetoothAdapter {
// Updates |devices_| to be consistent with |devices|.
void UpdateDevices(NSArray* devices);
- void MaybeStartDeviceInquiry();
- void MaybeStopDeviceInquiry();
-
- typedef std::vector<std::pair<base::Closure, ErrorCallback> >
- DiscoveryCallbackList;
- void RunCallbacks(const DiscoveryCallbackList& callback_list,
- bool success) const;
-
std::string address_;
std::string name_;
bool powered_;
- DiscoveryStatus discovery_status_;
- DiscoveryCallbackList on_start_discovery_callbacks_;
- DiscoveryCallbackList on_stop_discovery_callbacks_;
- size_t num_discovery_listeners_;
+ int num_discovery_sessions_;
- base::scoped_nsobject<BluetoothAdapterMacDelegate> adapter_delegate_;
- base::scoped_nsobject<IOBluetoothDeviceInquiry> device_inquiry_;
+ // Discovery manager for Bluetooth Classic.
+ scoped_ptr<BluetoothDiscoveryManagerMac> classic_discovery_manager_;
// A list of discovered device addresses.
// This list is used to check if the same device is discovered twice during
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index d870ca1..c4f9e39 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -5,7 +5,6 @@
#include "device/bluetooth/bluetooth_adapter_mac.h"
#import <IOBluetooth/objc/IOBluetoothDevice.h>
-#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
#import <IOBluetooth/objc/IOBluetoothHostController.h>
#include <string>
@@ -25,42 +24,6 @@
#include "device/bluetooth/bluetooth_socket_mac.h"
#include "device/bluetooth/bluetooth_uuid.h"
-@interface BluetoothAdapterMacDelegate
- : NSObject <IOBluetoothDeviceInquiryDelegate> {
- @private
- device::BluetoothAdapterMac* adapter_; // weak
-}
-
-- (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter;
-
-@end
-
-@implementation BluetoothAdapterMacDelegate
-
-- (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter {
- if ((self = [super init]))
- adapter_ = adapter;
-
- return self;
-}
-
-- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender {
- adapter_->DeviceInquiryStarted(sender);
-}
-
-- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
- device:(IOBluetoothDevice*)device {
- adapter_->DeviceFound(sender, device);
-}
-
-- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
- error:(IOReturn)error
- aborted:(BOOL)aborted {
- adapter_->DeviceInquiryComplete(sender, error, aborted);
-}
-
-@end
-
namespace {
const int kPollIntervalMs = 500;
@@ -85,13 +48,11 @@ base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() {
BluetoothAdapterMac::BluetoothAdapterMac()
: BluetoothAdapter(),
powered_(false),
- discovery_status_(NOT_DISCOVERING),
- adapter_delegate_(
- [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]),
- device_inquiry_(
- [[IOBluetoothDeviceInquiry
- inquiryWithDelegate:adapter_delegate_] retain]),
+ num_discovery_sessions_(0),
+ classic_discovery_manager_(
+ BluetoothDiscoveryManagerMac::CreateClassic(this)),
weak_ptr_factory_(this) {
+ DCHECK(classic_discovery_manager_.get());
}
BluetoothAdapterMac::~BluetoothAdapterMac() {
@@ -152,8 +113,7 @@ void BluetoothAdapterMac::SetDiscoverable(
}
bool BluetoothAdapterMac::IsDiscovering() const {
- return discovery_status_ == DISCOVERING ||
- discovery_status_ == DISCOVERY_STOPPING;
+ return classic_discovery_manager_->IsDiscovering();
}
void BluetoothAdapterMac::CreateRfcommService(
@@ -176,29 +136,86 @@ void BluetoothAdapterMac::CreateL2capService(
this, uuid, psm, base::Bind(callback, socket), error_callback);
}
+void BluetoothAdapterMac::DeviceFound(BluetoothDiscoveryManagerMac* manager,
+ IOBluetoothDevice* device) {
+ std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
+ if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
+ BluetoothDeviceMac device_mac(device);
+ FOR_EACH_OBSERVER(
+ BluetoothAdapter::Observer, observers_, DeviceAdded(this, &device_mac));
+ discovered_devices_.insert(device_address);
+ }
+}
+
+void BluetoothAdapterMac::DiscoveryStopped(
+ BluetoothDiscoveryManagerMac* manager,
+ bool unexpected) {
+ DCHECK_EQ(manager, classic_discovery_manager_.get());
+ if (unexpected) {
+ DVLOG(1) << "Discovery stopped unexpectedly";
+ num_discovery_sessions_ = 0;
+ MarkDiscoverySessionsAsInactive();
+ }
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
+ observers_,
+ AdapterDiscoveringChanged(this, false));
+}
+
void BluetoothAdapterMac::AddDiscoverySession(
const base::Closure& callback,
const ErrorCallback& error_callback) {
- if (discovery_status_ == DISCOVERING) {
- num_discovery_listeners_++;
+ DVLOG(1) << __func__;
+ if (num_discovery_sessions_ > 0) {
+ DCHECK(IsDiscovering());
+ num_discovery_sessions_++;
callback.Run();
return;
}
- on_start_discovery_callbacks_.push_back(
- std::make_pair(callback, error_callback));
- MaybeStartDeviceInquiry();
+
+ DCHECK_EQ(0, num_discovery_sessions_);
+
+ if (!classic_discovery_manager_->StartDiscovery()) {
+ DVLOG(1) << "Failed to add a discovery session";
+ error_callback.Run();
+ return;
+ }
+
+ DVLOG(1) << "Added a discovery session";
+ num_discovery_sessions_++;
+ FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
+ observers_,
+ AdapterDiscoveringChanged(this, true));
+ callback.Run();
}
void BluetoothAdapterMac::RemoveDiscoverySession(
const base::Closure& callback,
const ErrorCallback& error_callback) {
- if (discovery_status_ == NOT_DISCOVERING) {
+ DVLOG(1) << __func__;
+
+ if (num_discovery_sessions_ > 1) {
+ // There are active sessions other than the one currently being removed.
+ DCHECK(IsDiscovering());
+ num_discovery_sessions_--;
+ callback.Run();
+ return;
+ }
+
+ if (num_discovery_sessions_ == 0) {
+ DVLOG(1) << "No active discovery sessions. Returning error.";
error_callback.Run();
return;
}
- on_stop_discovery_callbacks_.push_back(
- std::make_pair(callback, error_callback));
- MaybeStopDeviceInquiry();
+
+ if (!classic_discovery_manager_->StopDiscovery()) {
+ DVLOG(1) << "Failed to stop discovery";
+ error_callback.Run();
+ return;
+ }
+
+ DVLOG(1) << "Discovery stopped";
+ num_discovery_sessions_--;
+ callback.Run();
}
void BluetoothAdapterMac::RemovePairingDelegateInternal(
@@ -264,6 +281,9 @@ void BluetoothAdapterMac::PollAdapter() {
}
void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
+ // TODO(armansito): This code never calls
+ // BluetoothAdapter::Observer::DeviceRemoved. It should, if a device
+ // no longer exists.
STLDeleteValues(&devices_);
for (IOBluetoothDevice* device in devices) {
std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
@@ -271,95 +291,4 @@ void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
}
}
-void BluetoothAdapterMac::DeviceInquiryStarted(
- IOBluetoothDeviceInquiry* inquiry) {
- DCHECK_EQ(device_inquiry_, inquiry);
- if (discovery_status_ == DISCOVERING)
- return;
-
- discovery_status_ = DISCOVERING;
- RunCallbacks(on_start_discovery_callbacks_, true);
- num_discovery_listeners_ = on_start_discovery_callbacks_.size();
- on_start_discovery_callbacks_.clear();
-
- FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
- AdapterDiscoveringChanged(this, true));
- MaybeStopDeviceInquiry();
-}
-
-void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry,
- IOBluetoothDevice* device) {
- DCHECK_EQ(device_inquiry_, inquiry);
- std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
- if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
- BluetoothDeviceMac device_mac(device);
- FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
- DeviceAdded(this, &device_mac));
- discovered_devices_.insert(device_address);
- }
-}
-
-void BluetoothAdapterMac::DeviceInquiryComplete(
- IOBluetoothDeviceInquiry* inquiry,
- IOReturn error,
- bool aborted) {
- DCHECK_EQ(device_inquiry_, inquiry);
- if (discovery_status_ == DISCOVERING &&
- [device_inquiry_ start] == kIOReturnSuccess) {
- return;
- }
-
- // Device discovery is done.
- discovered_devices_.clear();
- discovery_status_ = NOT_DISCOVERING;
- RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess);
- num_discovery_listeners_ = 0;
- on_stop_discovery_callbacks_.clear();
- FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
- AdapterDiscoveringChanged(this, false));
- MaybeStartDeviceInquiry();
-}
-
-void BluetoothAdapterMac::MaybeStartDeviceInquiry() {
- if (discovery_status_ == NOT_DISCOVERING &&
- !on_start_discovery_callbacks_.empty()) {
- discovery_status_ = DISCOVERY_STARTING;
- if ([device_inquiry_ start] != kIOReturnSuccess) {
- discovery_status_ = NOT_DISCOVERING;
- RunCallbacks(on_start_discovery_callbacks_, false);
- on_start_discovery_callbacks_.clear();
- }
- }
-}
-
-void BluetoothAdapterMac::MaybeStopDeviceInquiry() {
- if (discovery_status_ != DISCOVERING)
- return;
-
- if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) {
- RunCallbacks(on_stop_discovery_callbacks_, true);
- num_discovery_listeners_ -= on_stop_discovery_callbacks_.size();
- on_stop_discovery_callbacks_.clear();
- return;
- }
-
- discovery_status_ = DISCOVERY_STOPPING;
- if ([device_inquiry_ stop] != kIOReturnSuccess) {
- RunCallbacks(on_stop_discovery_callbacks_, false);
- on_stop_discovery_callbacks_.clear();
- }
-}
-
-void BluetoothAdapterMac::RunCallbacks(
- const DiscoveryCallbackList& callback_list, bool success) const {
- for (DiscoveryCallbackList::const_iterator iter = callback_list.begin();
- iter != callback_list.end();
- ++iter) {
- if (success)
- ui_task_runner_->PostTask(FROM_HERE, iter->first);
- else
- ui_task_runner_->PostTask(FROM_HERE, iter->second);
- }
-}
-
} // namespace device
diff --git a/device/bluetooth/bluetooth_discovery_manager_mac.h b/device/bluetooth/bluetooth_discovery_manager_mac.h
new file mode 100644
index 0000000..575a033
--- /dev/null
+++ b/device/bluetooth/bluetooth_discovery_manager_mac.h
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_DISCOVERY_MANAGER_MAC_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_DISCOVERY_MANAGER_MAC_H_
+
+#include "base/macros.h"
+
+@class IOBluetoothDevice;
+
+namespace device {
+
+// Class used by BluetoothAdapterMac to manage classic and LE device discovery.
+// For Bluetooth Classic, this class is responsible for keeping device inquiry
+// running if device discovery is initiated.
+class BluetoothDiscoveryManagerMac {
+ public:
+ // Interface for being notified of events during a device discovery session.
+ class Observer {
+ public:
+ // Called when |manager| has found a device through classic device inquiry
+ // in the form of a IOBluetoothDevice.
+ virtual void DeviceFound(BluetoothDiscoveryManagerMac* manager,
+ IOBluetoothDevice* device) {}
+
+ // Called when device discovery is no longer running, due to either a call
+ // to BluetoothDiscoveryManagerMac::StopDiscovery or an unexpected reason,
+ // such as when a user disables the controller, in which case the value of
+ // |unexpected| will be true.
+ virtual void DiscoveryStopped(BluetoothDiscoveryManagerMac* manager,
+ bool unexpected) {}
+ };
+
+ virtual ~BluetoothDiscoveryManagerMac();
+
+ // Returns true, if discovery is currently being performed.
+ virtual bool IsDiscovering() const = 0;
+
+ // Initiates a discovery session. Returns true on success or if discovery
+ // is already running. Returns false on failure.
+ virtual bool StartDiscovery() = 0;
+
+ // Stops a discovery session. Returns true on success or if discovery is
+ // already not running. Returns false on failure.
+ virtual bool StopDiscovery() = 0;
+
+ // Creates a discovery manager for Bluetooth Classic device discovery with
+ // observer |observer|. Note that the life-time of |observer| should not
+ // end before that of the returned BluetoothDiscoveryManager, as that may
+ // lead to use after free errors.
+ static BluetoothDiscoveryManagerMac* CreateClassic(Observer* observer);
+
+ protected:
+ explicit BluetoothDiscoveryManagerMac(Observer* observer);
+
+ // Observer interested in notifications from us.
+ Observer* observer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDiscoveryManagerMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_DISCOVERY_MANAGER_MAC_H_
diff --git a/device/bluetooth/bluetooth_discovery_manager_mac.mm b/device/bluetooth/bluetooth_discovery_manager_mac.mm
new file mode 100644
index 0000000..528e22d
--- /dev/null
+++ b/device/bluetooth/bluetooth_discovery_manager_mac.mm
@@ -0,0 +1,222 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_discovery_manager_mac.h"
+
+#import <IOBluetooth/objc/IOBluetoothDevice.h>
+#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/logging.h"
+
+namespace device {
+
+class BluetoothDiscoveryManagerMacClassic;
+
+} // namespace device
+
+// IOBluetoothDeviceInquiryDelegate implementation.
+@interface BluetoothDeviceInquiryDelegate
+ : NSObject<IOBluetoothDeviceInquiryDelegate> {
+ @private
+ device::BluetoothDiscoveryManagerMacClassic* manager_; // weak
+}
+
+- (id)initWithManager:(device::BluetoothDiscoveryManagerMacClassic*)manager;
+
+@end
+
+namespace device {
+
+// ementation of BluetoothDiscoveryManagerMac for Bluetooth classic device
+// discovery, using the IOBluetooth framework.
+class BluetoothDiscoveryManagerMacClassic
+ : public BluetoothDiscoveryManagerMac {
+ public:
+ explicit BluetoothDiscoveryManagerMacClassic(Observer* observer)
+ : BluetoothDiscoveryManagerMac(observer),
+ should_do_discovery_(false),
+ inquiry_running_(false),
+ inquiry_delegate_(
+ [[BluetoothDeviceInquiryDelegate alloc] initWithManager:this]),
+ inquiry_([[IOBluetoothDeviceInquiry alloc]
+ initWithDelegate:inquiry_delegate_]) {}
+
+ virtual ~BluetoothDiscoveryManagerMacClassic() {}
+
+ // BluetoothDiscoveryManagerMac override.
+ virtual bool IsDiscovering() const OVERRIDE { return should_do_discovery_; }
+
+ // BluetoothDiscoveryManagerMac override.
+ virtual bool StartDiscovery() OVERRIDE {
+ DVLOG(1) << "Bluetooth Classic: StartDiscovery";
+ DCHECK(!should_do_discovery_);
+
+ DVLOG(1) << "Discovery requested";
+ should_do_discovery_ = true;
+
+ if (inquiry_running_) {
+ DVLOG(1) << "Device inquiry already running";
+ return true;
+ }
+
+ DVLOG(1) << "Requesting to start device inquiry";
+ if ([inquiry_ start] != kIOReturnSuccess) {
+ DVLOG(1) << "Failed to start device inquiry";
+
+ // Set |should_do_discovery_| to false here. Since we're reporting an
+ // error, we're indicating that the adapter call StartDiscovery again
+ // if needed.
+ should_do_discovery_ = false;
+ return false;
+ }
+
+ DVLOG(1) << "Device inquiry start was successful";
+ return true;
+ }
+
+ // BluetoothDiscoveryManagerMac override.
+ virtual bool StopDiscovery() OVERRIDE {
+ DVLOG(1) << "Bluetooth Classic: StopDiscovery";
+ DCHECK(should_do_discovery_);
+
+ should_do_discovery_ = false;
+
+ if (!inquiry_running_) {
+ DVLOG(1) << "No device inquiry running; discovery stopped";
+ return true;
+ }
+
+ DVLOG(1) << "Requesting to stop device inquiry";
+ IOReturn status = [inquiry_ stop];
+ if (status == kIOReturnSuccess) {
+ DVLOG(1) << "Device inquiry stop was successful";
+ return true;
+ }
+
+ if (status == kIOReturnNotPermitted) {
+ DVLOG(1) << "Device inquiry was already stopped";
+ return true;
+ }
+
+ LOG(WARNING) << "Failed to stop device inquiry";
+ return false;
+ }
+
+ // Called by BluetoothDeviceInquiryDelegate.
+ void DeviceInquiryStarted(IOBluetoothDeviceInquiry* inquiry) {
+ DCHECK(!inquiry_running_);
+
+ DVLOG(1) << "Device inquiry started!";
+
+ // If discovery was requested to stop in the mean time, stop the inquiry.
+ if (!should_do_discovery_) {
+ DVLOG(1) << "Discovery stop was requested earlier. Stopping inquiry";
+ [inquiry stop];
+ return;
+ }
+
+ inquiry_running_ = true;
+ }
+
+ void DeviceFound(IOBluetoothDeviceInquiry* inquiry,
+ IOBluetoothDevice* device) {
+ DCHECK(observer_);
+ observer_->DeviceFound(this, device);
+ }
+
+ void DeviceInquiryComplete(IOBluetoothDeviceInquiry* inquiry,
+ IOReturn error,
+ bool aborted) {
+ DCHECK_EQ(inquiry_, inquiry);
+ DCHECK(observer_);
+ DVLOG(1) << "Device inquiry complete";
+ inquiry_running_ = false;
+
+ // If discovery is no longer desired, notify observers that discovery
+ // has stopped and return.
+ if (!should_do_discovery_) {
+ observer_->DiscoveryStopped(this, false /* unexpected */);
+ return;
+ }
+
+ // If discovery has stopped due to an unexpected reason, notify the
+ // observers and return.
+ if (error != kIOReturnSuccess) {
+ DVLOG(1) << "Inquiry has stopped with an error: " << error;
+ should_do_discovery_ = false;
+ observer_->DiscoveryStopped(this, true /* unexpected */);
+ return;
+ }
+
+ DVLOG(1) << "Restarting device inquiry";
+
+ if ([inquiry_ start] == kIOReturnSuccess) {
+ DVLOG(1) << "Device inquiry restart was successful";
+ return;
+ }
+
+ DVLOG(1) << "Failed to restart discovery";
+ should_do_discovery_ = false;
+ DCHECK(observer_);
+ observer_->DiscoveryStopped(this, true /* unexpected */);
+ }
+
+ private:
+ // The requested discovery state.
+ bool should_do_discovery_;
+
+ // The current inquiry state.
+ bool inquiry_running_;
+
+ // Objective-C objects for running and tracking device inquiry.
+ base::scoped_nsobject<BluetoothDeviceInquiryDelegate> inquiry_delegate_;
+ base::scoped_nsobject<IOBluetoothDeviceInquiry> inquiry_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDiscoveryManagerMacClassic);
+};
+
+BluetoothDiscoveryManagerMac::BluetoothDiscoveryManagerMac(
+ Observer* observer) : observer_(observer) {
+ DCHECK(observer);
+}
+
+BluetoothDiscoveryManagerMac::~BluetoothDiscoveryManagerMac() {
+}
+
+// static
+BluetoothDiscoveryManagerMac* BluetoothDiscoveryManagerMac::CreateClassic(
+ Observer* observer) {
+ return new BluetoothDiscoveryManagerMacClassic(observer);
+}
+
+} // namespace device
+
+@implementation BluetoothDeviceInquiryDelegate
+
+- (id)initWithManager:
+ (device::BluetoothDiscoveryManagerMacClassic*)manager {
+ if ((self = [super init]))
+ manager_ = manager;
+
+ return self;
+}
+
+- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender {
+ manager_->DeviceInquiryStarted(sender);
+}
+
+- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
+ device:(IOBluetoothDevice*)device {
+ manager_->DeviceFound(sender, device);
+}
+
+- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
+ error:(IOReturn)error
+ aborted:(BOOL)aborted {
+ manager_->DeviceInquiryComplete(sender, error, aborted);
+}
+
+@end