diff options
author | jpawlowski <jpawlowski@chromium.org> | 2015-04-20 16:41:30 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-20 23:41:40 +0000 |
commit | 909a4810497de84a03bcb1accf7ca606371ce444 (patch) | |
tree | af5b6a5e53b5f19bdc252a033804723de6c4c9c7 /device | |
parent | d819416ed0e47918577d7f3f24765a20d9f506f6 (diff) | |
download | chromium_src-909a4810497de84a03bcb1accf7ca606371ce444.zip chromium_src-909a4810497de84a03bcb1accf7ca606371ce444.tar.gz chromium_src-909a4810497de84a03bcb1accf7ca606371ce444.tar.bz2 |
Implement SetDiscoveryFilter for ChromiumOS
BUG=407773
R=armansito@chromium.org
Review URL: https://codereview.chromium.org/1082173002
Cr-Commit-Position: refs/heads/master@{#325939}
Diffstat (limited to 'device')
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.cc | 156 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.h | 21 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_chromeos_unittest.cc | 736 |
3 files changed, 904 insertions, 9 deletions
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc index fce8f8b..b9cdd09 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.cc +++ b/device/bluetooth/bluetooth_adapter_chromeos.cc @@ -1106,7 +1106,8 @@ void BluetoothAdapterChromeOS::AddDiscoverySession( DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0); VLOG(1) << "Pending request to start/stop device discovery. Queueing " << "request to start a new discovery session."; - discovery_request_queue_.push(std::make_pair(callback, error_callback)); + discovery_request_queue_.push( + std::make_tuple(discovery_filter, callback, error_callback)); return; } @@ -1115,13 +1116,31 @@ void BluetoothAdapterChromeOS::AddDiscoverySession( DCHECK(IsDiscovering()); DCHECK(!discovery_request_pending_); num_discovery_sessions_++; - callback.Run(); + SetDiscoveryFilter(BluetoothDiscoveryFilter::Merge( + GetMergedDiscoveryFilter().get(), discovery_filter), + callback, error_callback); return; } // There are no active discovery sessions. DCHECK_EQ(num_discovery_sessions_, 0); + if (discovery_filter) { + discovery_request_pending_ = true; + + scoped_ptr<BluetoothDiscoveryFilter> df(new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL)); + df->CopyFrom(*discovery_filter); + SetDiscoveryFilter( + df.Pass(), + base::Bind(&BluetoothAdapterChromeOS::OnPreSetDiscoveryFilter, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback), + base::Bind(&BluetoothAdapterChromeOS::OnPreSetDiscoveryFilterError, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback)); + return; + } else + current_filter_.reset(); + // This is the first request to start device discovery. discovery_request_pending_ = true; DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery( @@ -1147,7 +1166,9 @@ void BluetoothAdapterChromeOS::RemoveDiscoverySession( DCHECK(IsDiscovering()); DCHECK(!discovery_request_pending_); num_discovery_sessions_--; - callback.Run(); + + SetDiscoveryFilter(GetMergedDiscoveryFilterMasked(discovery_filter), + callback, error_callback); return; } @@ -1188,7 +1209,69 @@ void BluetoothAdapterChromeOS::SetDiscoveryFilter( scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { - // TODO(jpawlowski): Implement + if (!IsPresent()) { + error_callback.Run(); + return; + } + + // If old and new filter are equal (null) then don't make request, just call + // succes callback + if (!current_filter_ && !discovery_filter.get()) { + callback.Run(); + return; + } + + // If old and new filter are not null and equal then don't make request, just + // call succes callback + if (current_filter_ && discovery_filter && + current_filter_->Equals(*discovery_filter)) { + callback.Run(); + return; + } + + current_filter_.reset(discovery_filter.release()); + + chromeos::BluetoothAdapterClient::DiscoveryFilter dbus_discovery_filter; + + if (current_filter_.get()) { + uint16_t pathloss; + int16_t rssi; + uint8_t transport; + std::set<device::BluetoothUUID> uuids; + + if (current_filter_->GetPathloss(&pathloss)) + dbus_discovery_filter.pathloss.reset(new uint16_t(pathloss)); + + if (current_filter_->GetRSSI(&rssi)) + dbus_discovery_filter.rssi.reset(new int16_t(rssi)); + + transport = current_filter_->GetTransport(); + if (transport == BluetoothDiscoveryFilter::Transport::TRANSPORT_LE) { + dbus_discovery_filter.transport.reset(new std::string("le")); + } else if (transport == + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC) { + dbus_discovery_filter.transport.reset(new std::string("bredr")); + } else if (transport == + BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL) { + dbus_discovery_filter.transport.reset(new std::string("auto")); + } + + current_filter_->GetUUIDs(uuids); + if (uuids.size()) { + dbus_discovery_filter.uuids = + scoped_ptr<std::vector<std::string>>(new std::vector<std::string>); + + for (const auto& it : uuids) + dbus_discovery_filter.uuids.get()->push_back(it.value()); + } + } + + DBusThreadManager::Get()->GetBluetoothAdapterClient()->SetDiscoveryFilter( + object_path_, dbus_discovery_filter, + base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoveryFilter, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback), + base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoveryFilterError, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback)); } void BluetoothAdapterChromeOS::OnStartDiscovery( @@ -1247,6 +1330,8 @@ void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) { num_discovery_sessions_--; callback.Run(); + current_filter_.reset(); + // Try to add a new discovery session for each queued request. ProcessQueuedDiscoveryRequests(); } @@ -1268,12 +1353,71 @@ void BluetoothAdapterChromeOS::OnStopDiscoveryError( ProcessQueuedDiscoveryRequests(); } +void BluetoothAdapterChromeOS::OnPreSetDiscoveryFilter( + const base::Closure& callback, + const ErrorCallback& error_callback) { + // This is the first request to start device discovery. + DCHECK(discovery_request_pending_); + DCHECK_EQ(num_discovery_sessions_, 0); + + DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery( + object_path_, + base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback), + base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError, + weak_ptr_factory_.GetWeakPtr(), callback, error_callback)); +} + +void BluetoothAdapterChromeOS::OnPreSetDiscoveryFilterError( + const base::Closure& callback, + const ErrorCallback& error_callback) { + LOG(WARNING) << object_path_.value() + << ": Failed to pre set discovery filter."; + + // Failed to start discovery. This can only happen if the count is at 0. + DCHECK_EQ(num_discovery_sessions_, 0); + DCHECK(discovery_request_pending_); + discovery_request_pending_ = false; + + error_callback.Run(); + + // Try to add a new discovery session for each queued request. + ProcessQueuedDiscoveryRequests(); +} + +void BluetoothAdapterChromeOS::OnSetDiscoveryFilter( + const base::Closure& callback, + const ErrorCallback& error_callback) { + // Report success on the original request and increment the count. + VLOG(1) << __func__; + if (IsPresent()) + callback.Run(); + else + error_callback.Run(); +} + +void BluetoothAdapterChromeOS::OnSetDiscoveryFilterError( + const base::Closure& callback, + const ErrorCallback& error_callback, + const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << object_path_.value() + << ": Failed to set discovery filter: " << error_name << ": " + << error_message; + + error_callback.Run(); + + // Try to add a new discovery session for each queued request. + ProcessQueuedDiscoveryRequests(); +} + void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() { while (!discovery_request_queue_.empty()) { VLOG(1) << "Process queued discovery request."; - DiscoveryCallbackPair callbacks = discovery_request_queue_.front(); + DiscoveryParamTuple params = discovery_request_queue_.front(); discovery_request_queue_.pop(); - AddDiscoverySession(nullptr, callbacks.first, callbacks.second); + AddDiscoverySession(std::get<0>(params), std::get<1>(params), + std::get<2>(params)); // If the queued request resulted in a pending call, then let it // asynchonously process the remaining queued requests once the pending diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h index 39a23de..cc5fb1d 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.h +++ b/device/bluetooth/bluetooth_adapter_chromeos.h @@ -167,8 +167,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS // typedef for callback parameters that are passed to AddDiscoverySession // and RemoveDiscoverySession. This is used to queue incoming requests while // a call to BlueZ is pending. - typedef std::pair<base::Closure, ErrorCallback> DiscoveryCallbackPair; - typedef std::queue<DiscoveryCallbackPair> DiscoveryCallbackQueue; + typedef std::tuple<device::BluetoothDiscoveryFilter*, + base::Closure, + ErrorCallback> DiscoveryParamTuple; + typedef std::queue<DiscoveryParamTuple> DiscoveryCallbackQueue; BluetoothAdapterChromeOS(); ~BluetoothAdapterChromeOS() override; @@ -290,6 +292,17 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS const std::string& error_name, const std::string& error_message); + void OnPreSetDiscoveryFilter(const base::Closure& callback, + const ErrorCallback& error_callback); + void OnPreSetDiscoveryFilterError(const base::Closure& callback, + const ErrorCallback& error_callback); + void OnSetDiscoveryFilter(const base::Closure& callback, + const ErrorCallback& error_callback); + void OnSetDiscoveryFilterError(const base::Closure& callback, + const ErrorCallback& error_callback, + const std::string& error_name, + const std::string& error_message); + // Called by dbus:: on completion of the D-Bus method to register a profile. void OnRegisterProfile(const device::BluetoothUUID& uuid, scoped_ptr<BluetoothAdapterProfileChromeOS> profile); @@ -307,7 +320,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS // remain. void RemoveProfile(const device::BluetoothUUID& uuid); - // Processes the queued discovery requests. For each DiscoveryCallbackPair in + // Processes the queued discovery requests. For each DiscoveryParamTuple in // the queue, this method will try to add a new discovery session. This method // is called whenever a pending D-Bus call to start or stop discovery has // ended (with either success or failure). @@ -358,6 +371,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS std::map<device::BluetoothUUID, std::vector<RegisterProfileCompletionPair>*> profile_queues_; + scoped_ptr<device::BluetoothDiscoveryFilter> current_filter_; + // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory<BluetoothAdapterChromeOS> weak_ptr_factory_; diff --git a/device/bluetooth/bluetooth_chromeos_unittest.cc b/device/bluetooth/bluetooth_chromeos_unittest.cc index 535e047..1a71c5b 100644 --- a/device/bluetooth/bluetooth_chromeos_unittest.cc +++ b/device/bluetooth/bluetooth_chromeos_unittest.cc @@ -27,6 +27,7 @@ using device::BluetoothAdapter; using device::BluetoothAdapterFactory; using device::BluetoothAudioSink; using device::BluetoothDevice; +using device::BluetoothDiscoveryFilter; using device::BluetoothDiscoverySession; using device::BluetoothUUID; @@ -1422,6 +1423,741 @@ TEST_F(BluetoothChromeOSTest, StartDiscoverySession) { EXPECT_FALSE(adapter_->IsDiscovering()); } +TEST_F(BluetoothChromeOSTest, SetDiscoveryFilterBeforeStartDiscovery) { + // Test a simulated discovery session. + fake_bluetooth_device_client_->SetSimulationIntervalMs(10); + GetAdapter(); + + TestObserver observer(adapter_); + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop_.Run(); + EXPECT_EQ(2, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_TRUE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)1, discovery_sessions_.size()); + ASSERT_TRUE(discovery_sessions_[0]->IsActive()); + ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_NE(nullptr, filter); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-60, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + + discovery_sessions_[0]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_FALSE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)1, discovery_sessions_.size()); + ASSERT_FALSE(discovery_sessions_[0]->IsActive()); + ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), + (BluetoothDiscoveryFilter*)NULL); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); +} + +TEST_F(BluetoothChromeOSTest, SetDiscoveryFilterBeforeStartDiscoveryFail) { + // Test a simulated discovery session. + fake_bluetooth_device_client_->SetSimulationIntervalMs(10); + GetAdapter(); + + TestObserver observer(adapter_); + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, callback_count_); + callback_count_ = 0; + + fake_bluetooth_adapter_client_->MakeSetDiscoveryFilterFail(); + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + EXPECT_EQ(1, error_callback_count_); + error_callback_count_ = 0; + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_FALSE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)0, discovery_sessions_.size()); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); +} + +// This test queues two requests to StartDiscovery with pre set filter. This +// should result in SetDiscoveryFilter, then StartDiscovery, and SetDiscovery +// DBus calls +TEST_F(BluetoothChromeOSTest, QueuedSetDiscoveryFilterBeforeStartDiscovery) { + // Test a simulated discovery session. + fake_bluetooth_device_client_->SetSimulationIntervalMs(10); + GetAdapter(); + + TestObserver observer(adapter_); + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df2->SetRSSI(-65); + df2->AddUUID(BluetoothUUID("1002")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); + + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + // Queue two requests to start discovery session with filter. + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter2.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + // Run requests, on DBus level there should be call SetDiscoveryFilter, then + // StartDiscovery, then SetDiscoveryFilter again. + message_loop_.Run(); + message_loop_.Run(); + + EXPECT_EQ(2, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_TRUE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)2, discovery_sessions_.size()); + ASSERT_TRUE(discovery_sessions_[0]->IsActive()); + ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); + ASSERT_TRUE(discovery_sessions_[1]->IsActive()); + ASSERT_TRUE(df2->Equals(*discovery_sessions_[1]->GetDiscoveryFilter())); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_NE(nullptr, filter); + EXPECT_EQ("auto", *filter->transport); + EXPECT_EQ(-65, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + auto uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1002")); + + discovery_sessions_[0]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + discovery_sessions_[1]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + EXPECT_EQ(2, callback_count_); + EXPECT_EQ(0, error_callback_count_); + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_FALSE(adapter_->IsDiscovering()); + ASSERT_FALSE(discovery_sessions_[0]->IsActive()); + ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), + (BluetoothDiscoveryFilter*)NULL); + ASSERT_FALSE(discovery_sessions_[1]->IsActive()); + ASSERT_EQ(discovery_sessions_[1]->GetDiscoveryFilter(), + (BluetoothDiscoveryFilter*)NULL); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); +} + +// Call StartFilteredDiscovery twice (2nd time while 1st call is still pending). +// Make the first SetDiscoveryFilter fail and the second one succeed. It should +// end up with one active discovery session. +TEST_F(BluetoothChromeOSTest, + QueuedSetDiscoveryFilterBeforeStartDiscoveryFail) { + // Test a simulated discovery session. + fake_bluetooth_device_client_->SetSimulationIntervalMs(10); + GetAdapter(); + + TestObserver observer(adapter_); + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df2->SetRSSI(-65); + df2->AddUUID(BluetoothUUID("1002")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); + + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + fake_bluetooth_adapter_client_->MakeSetDiscoveryFilterFail(); + + // Queue two requests to start discovery session with filter. + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter2.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + // First request to SetDiscoveryFilter should fail, resulting in no session + // being created. + EXPECT_EQ(0, callback_count_); + EXPECT_EQ(1, error_callback_count_); + error_callback_count_ = 0; + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_FALSE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)0, discovery_sessions_.size()); + + message_loop_.Run(); + + // Second request should succeed + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + ASSERT_TRUE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)1, discovery_sessions_.size()); + ASSERT_TRUE(discovery_sessions_[0]->IsActive()); + ASSERT_TRUE(df2->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_NE(nullptr, filter); + EXPECT_EQ("bredr", *filter->transport); + EXPECT_EQ(-65, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + auto uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1002")); + + discovery_sessions_[0]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_FALSE(adapter_->IsDiscovering()); + ASSERT_FALSE(discovery_sessions_[0]->IsActive()); + ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), + (BluetoothDiscoveryFilter*)NULL); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); +} + +TEST_F(BluetoothChromeOSTest, SetDiscoveryFilterAfterStartDiscovery) { + // Test a simulated discovery session. + fake_bluetooth_device_client_->SetSimulationIntervalMs(10); + GetAdapter(); + + TestObserver observer(adapter_); + + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + adapter_->StartDiscoverySession( + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop_.Run(); + EXPECT_EQ(2, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_TRUE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)1, discovery_sessions_.size()); + ASSERT_TRUE(discovery_sessions_[0]->IsActive()); + EXPECT_EQ(1, observer.discovering_changed_count_); + observer.discovering_changed_count_ = 0; + + auto nullInstance = scoped_ptr<BluetoothDiscoveryFilter>(); + nullInstance.reset(); + ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), nullInstance.get()); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + discovery_sessions_[0]->SetDiscoveryFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + callback_count_ = 0; + + ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_NE(nullptr, filter); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-60, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + + discovery_sessions_[0]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_FALSE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)1, discovery_sessions_.size()); + ASSERT_FALSE(discovery_sessions_[0]->IsActive()); + ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), + (BluetoothDiscoveryFilter*)NULL); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); +} + +// This unit test asserts that the basic reference counting, and filter merging +// works correctly for discovery requests done via the BluetoothAdapter. +TEST_F(BluetoothChromeOSTest, SetDiscoveryFilterBeforeStartDiscoveryMultiple) { + GetAdapter(); + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsPowered()); + callback_count_ = 0; + + TestObserver observer(adapter_); + + // Request device discovery with pre-set filter 3 times. + for (int i = 0; i < 3; i++) { + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter; + if (i == 0) { + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-85); + df->AddUUID(BluetoothUUID("1000")); + discovery_filter.reset(df); + } else if (i == 1) { + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1020")); + df->AddUUID(BluetoothUUID("1001")); + discovery_filter.reset(df); + } else if (i == 2) { + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-65); + df->AddUUID(BluetoothUUID("1020")); + df->AddUUID(BluetoothUUID("1003")); + discovery_filter.reset(df); + } + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + if (i == 0) { + EXPECT_EQ(1, observer.discovering_changed_count_); + observer.discovering_changed_count_ = 0; + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-85, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + } else if (i == 1) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-85, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + } else if (i == 2) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-85, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + } + } + + // the success callback should have been called 3 times and the adapter should + // be discovering. + EXPECT_EQ(3, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)3, discovery_sessions_.size()); + + callback_count_ = 0; + // Request to stop discovery twice. + for (int i = 0; i < 2; i++) { + discovery_sessions_[i]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop_.Run(); + + if (i == 0) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-65, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_EQ(3UL, uuids.size()); + EXPECT_EQ(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + } else if (i == 1) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-65, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_EQ(2UL, uuids.size()); + EXPECT_EQ(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_EQ(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + } else if (i == 2) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-65, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_EQ(0UL, uuids.size()); + } + } + + // The success callback should have been called 2 times and the adapter should + // still be discovering. + EXPECT_EQ(2, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_FALSE(discovery_sessions_[0]->IsActive()); + EXPECT_FALSE(discovery_sessions_[1]->IsActive()); + EXPECT_TRUE(discovery_sessions_[2]->IsActive()); + + callback_count_ = 0; + + // Request device discovery 3 times. + for (int i = 0; i < 3; i++) { + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter; + + if (i == 0) { + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-85); + df->AddUUID(BluetoothUUID("1000")); + discovery_filter.reset(df); + } else if (i == 1) { + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1020")); + df->AddUUID(BluetoothUUID("1001")); + discovery_filter.reset(df); + } else if (i == 2) { + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-65); + df->AddUUID(BluetoothUUID("1020")); + df->AddUUID(BluetoothUUID("1003")); + discovery_filter.reset(df); + } + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + // each result in 1 requests. + message_loop_.Run(); + + if (i == 0) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-85, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + } else if (i == 1 || i == 2) { + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-85, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + } + } + + // The success callback should have been called 3 times and the adapter should + // still be discovering. + EXPECT_EQ(3, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsDiscovering()); + ASSERT_EQ((size_t)6, discovery_sessions_.size()); + + callback_count_ = 0; + // Request to stop discovery 4 times. + for (int i = 2; i < 6; i++) { + discovery_sessions_[i]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + // filter no 2 is same as filter no 5, so removing it shouldn't cause any + // filter update + if (i != 2 && i != 5) + message_loop_.Run(); + } + // Run only once, as there should have been one D-Bus call. + message_loop_.Run(); + + // The success callback should have been called 4 times and the adapter should + // no longer be discovering. + EXPECT_EQ(4, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(1, observer.discovering_changed_count_); + observer.discovering_changed_count_ = 0; + + // All discovery sessions should be inactive. + for (int i = 0; i < 6; i++) + EXPECT_FALSE(discovery_sessions_[i]->IsActive()); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ(nullptr, filter); +} + +// This unit test asserts that filter merging logic works correctly for filtered +// discovery requests done via the BluetoothAdapter. +TEST_F(BluetoothChromeOSTest, SetDiscoveryFilterMergingTest) { + GetAdapter(); + adapter_->SetPowered(true, base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-15); + df->AddUUID(BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-15, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + std::vector<std::string> uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + + df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(BluetoothUUID("1020")); + df->AddUUID(BluetoothUUID("1001")); + discovery_filter = scoped_ptr<BluetoothDiscoveryFilter>(df); + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("le", *filter->transport); + EXPECT_EQ(-60, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + + BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df3->SetRSSI(-65); + df3->AddUUID(BluetoothUUID("1020")); + df3->AddUUID(BluetoothUUID("1003")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3); + + adapter_->StartDiscoverySessionWithFilter( + discovery_filter3.Pass(), + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("auto", *filter->transport); + EXPECT_EQ(-65, *filter->rssi); + EXPECT_EQ(nullptr, filter->pathloss.get()); + uuids = *filter->uuids; + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); + EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); + + // start additionally classic scan + adapter_->StartDiscoverySession( + base::Bind(&BluetoothChromeOSTest::DiscoverySessionCallback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + message_loop_.Run(); + + filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); + EXPECT_EQ("auto", *filter->transport); + EXPECT_EQ(nullptr, filter->rssi.get()); + EXPECT_EQ(nullptr, filter->pathloss.get()); + EXPECT_EQ(nullptr, filter->uuids.get()); + + // Request to stop discovery 4 times. + for (int i = 3; i >= 0; i--) { + discovery_sessions_[i]->Stop( + base::Bind(&BluetoothChromeOSTest::Callback, base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + // Every session stopping would trigger filter update + message_loop_.Run(); + } +} + TEST_F(BluetoothChromeOSTest, DeviceProperties) { GetAdapter(); |