Index: device/bluetooth/bluetooth_adapter_mac.mm |
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm |
index 6fb2b44e6cc072fb0ad8fe01bf0dd41ee29f1d73..0ee87f42ad738464be3a68e4406a7389598e9d3f 100644 |
--- a/device/bluetooth/bluetooth_adapter_mac.mm |
+++ b/device/bluetooth/bluetooth_adapter_mac.mm |
@@ -44,38 +44,38 @@ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
#endif // MAC_OS_X_VERSION_10_7 |
-@interface BluetoothAdapterMacDelegate |
- : NSObject <IOBluetoothDeviceInquiryDelegate> { |
+@interface BluetoothDeviceInquiryDelegate |
+ : NSObject<IOBluetoothDeviceInquiryDelegate> { |
@private |
- device::BluetoothAdapterMac* adapter_; // weak |
+ device::BluetoothMacClassicDiscoveryManager* manager_; // weak |
} |
-- (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter; |
+- (id)initWithManager:(device::BluetoothMacClassicDiscoveryManager*)manager; |
@end |
-@implementation BluetoothAdapterMacDelegate |
+@implementation BluetoothDeviceInquiryDelegate |
-- (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter { |
+- (id)initWithManager:(device::BluetoothMacClassicDiscoveryManager*)manager { |
if ((self = [super init])) |
- adapter_ = adapter; |
+ manager_ = manager; |
return self; |
} |
- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender { |
- adapter_->DeviceInquiryStarted(sender); |
+ manager_->DeviceInquiryStarted(sender); |
} |
- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender |
device:(IOBluetoothDevice*)device { |
- adapter_->DeviceFound(sender, device); |
+ manager_->DeviceFound(sender, device); |
} |
- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender |
error:(IOReturn)error |
aborted:(BOOL)aborted { |
- adapter_->DeviceInquiryComplete(sender, error, aborted); |
+ manager_->DeviceInquiryComplete(sender, error, aborted); |
} |
@end |
@@ -101,15 +101,145 @@ base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { |
return adapter->weak_ptr_factory_.GetWeakPtr(); |
} |
+BluetoothMacClassicDiscoveryManager::BluetoothMacClassicDiscoveryManager( |
+ BluetoothAdapterMac* adapter) |
+ : should_do_discovery_(false), |
+ inquiry_running_(false), |
+ adapter_(adapter), |
+ inquiry_delegate_( |
+ [[BluetoothDeviceInquiryDelegate alloc] initWithManager:this]), |
+ inquiry_([[IOBluetoothDeviceInquiry alloc] |
+ initWithDelegate:inquiry_delegate_]) { |
+} |
+ |
+BluetoothMacClassicDiscoveryManager::~BluetoothMacClassicDiscoveryManager() { |
+} |
+ |
+bool BluetoothMacClassicDiscoveryManager::IsDiscovering() const { |
+ return should_do_discovery_; |
+} |
+ |
+bool BluetoothMacClassicDiscoveryManager::StartDiscovery() { |
+ VLOG(1) << "Bluetooth Classic: StartDiscovery"; |
+ if (should_do_discovery_) { |
+ VLOG(1) << "Already discovering"; |
+ return true; |
+ } |
+ |
+ VLOG(1) << "Discovery requested"; |
+ should_do_discovery_ = true; |
+ |
+ if (inquiry_running_) { |
+ VLOG(1) << "Device inquiry already running"; |
+ return true; |
+ } |
+ |
+ VLOG(1) << "Requesting to start device inquiry"; |
+ if ([inquiry_ start] != kIOReturnSuccess) { |
+ VLOG(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; |
+ } |
+ |
+ VLOG(1) << "Device inquiry start was successful"; |
+ return true; |
+} |
+ |
+bool BluetoothMacClassicDiscoveryManager::StopDiscovery() { |
+ VLOG(1) << "Bluetooth Classic: StopDiscovery"; |
+ if (!should_do_discovery_) { |
+ VLOG(1) << "Discovery already stopped"; |
+ return true; |
+ } |
+ |
+ should_do_discovery_ = false; |
+ |
+ if (!inquiry_running_) { |
+ VLOG(1) << "No device inquiry running; discovery stopped"; |
+ return true; |
+ } |
+ |
+ VLOG(1) << "Requesting to stop device inquiry"; |
+ IOReturn status = [inquiry_ stop]; |
+ if (status == kIOReturnSuccess) { |
+ VLOG(1) << "Device inquiry stop was successful"; |
+ return true; |
+ } |
+ |
+ if (status == kIOReturnNotPermitted) { |
+ VLOG(1) << "Device inquiry was already stopped"; |
+ return true; |
+ } |
+ |
+ LOG(WARNING) << "Failed to stop device inquiry"; |
+ return false; |
+} |
+ |
+void BluetoothMacClassicDiscoveryManager::DeviceInquiryStarted( |
+ IOBluetoothDeviceInquiry* inquiry) { |
+ DCHECK(!inquiry_running_); |
+ |
+ VLOG(1) << "Device inquiry started!"; |
+ |
+ // If discovery was requested to stop in the mean time, stop the inquiry. |
+ if (!should_do_discovery_) { |
+ VLOG(1) << "Discovery stop was requested earlier. Stopping inquiry"; |
+ [inquiry stop]; |
+ return; |
+ } |
+ |
+ inquiry_running_ = true; |
+} |
+ |
+void BluetoothMacClassicDiscoveryManager::DeviceFound( |
+ IOBluetoothDeviceInquiry* inquiry, |
+ IOBluetoothDevice* device) { |
+ adapter_->DeviceFound(device); |
+} |
+ |
+void BluetoothMacClassicDiscoveryManager::DeviceInquiryComplete( |
+ IOBluetoothDeviceInquiry* inquiry, |
+ IOReturn error, |
+ bool aborted) { |
+ DCHECK_EQ(inquiry_, inquiry); |
+ VLOG(1) << "Device inquiry complete"; |
+ inquiry_running_ = false; |
+ |
+ // Automatically restart device inquiry if discovery is still desired. |
+ if (!should_do_discovery_) { |
+ adapter_->ClassicDiscoveryStopped(false /* unexpected */); |
+ return; |
+ } |
+ |
+ if (error != kIOReturnSuccess) { |
+ VLOG(1) << "Inquiry has stopped with an error: " << error; |
+ should_do_discovery_ = false; |
+ adapter_->ClassicDiscoveryStopped(true /* unexpected */); |
+ return; |
+ } |
+ |
+ VLOG(1) << "Restarting device inquiry"; |
+ |
+ if ([inquiry_ start] == kIOReturnSuccess) { |
+ VLOG(1) << "Device inquiry restart was successful"; |
+ return; |
+ } |
+ |
+ VLOG(1) << "Failed to restart discovery"; |
+ should_do_discovery_ = false; |
+ adapter_->ClassicDiscoveryStopped(true /* unexpected */); |
+} |
+ |
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_session_manager_( |
+ new BluetoothMacClassicDiscoveryManager(this)), |
weak_ptr_factory_(this) { |
} |
@@ -171,8 +301,7 @@ void BluetoothAdapterMac::SetDiscoverable( |
} |
bool BluetoothAdapterMac::IsDiscovering() const { |
- return discovery_status_ == DISCOVERING || |
- discovery_status_ == DISCOVERY_STOPPING; |
+ return classic_discovery_session_manager_->IsDiscovering(); |
} |
void BluetoothAdapterMac::CreateRfcommService( |
@@ -194,29 +323,82 @@ void BluetoothAdapterMac::CreateL2capService( |
NOTIMPLEMENTED(); |
} |
+void BluetoothAdapterMac::DeviceFound(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::ClassicDiscoveryStopped(bool unexpected) { |
+ if (unexpected) { |
+ VLOG(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_++; |
+ VLOG(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(num_discovery_sessions_ == 0); |
+ |
+ if (!classic_discovery_session_manager_->StartDiscovery()) { |
+ VLOG(1) << "Failed to add a discovery session"; |
+ error_callback.Run(); |
+ return; |
+ } |
+ |
+ VLOG(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) { |
+ VLOG(1) << __func__; |
+ |
+ // There are active sessions other than the one currently being removed. |
+ if (num_discovery_sessions_ > 1) { |
+ DCHECK(IsDiscovering()); |
+ num_discovery_sessions_--; |
+ callback.Run(); |
+ return; |
+ } |
+ |
+ if (num_discovery_sessions_ == 0) { |
+ VLOG(1) << "No active discovery sessions. Returning error."; |
+ error_callback.Run(); |
+ return; |
+ } |
+ |
+ if (!classic_discovery_session_manager_->StopDiscovery()) { |
+ VLOG(1) << "Failed to stop discovery"; |
error_callback.Run(); |
return; |
} |
- on_stop_discovery_callbacks_.push_back( |
- std::make_pair(callback, error_callback)); |
- MaybeStopDeviceInquiry(); |
+ |
+ VLOG(1) << "Discovery stopped"; |
+ num_discovery_sessions_--; |
+ callback.Run(); |
} |
void BluetoothAdapterMac::RemovePairingDelegateInternal( |
@@ -282,6 +464,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); |
@@ -289,95 +474,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 |