diff --git a/fastpair/internal/mediums/BUILD b/fastpair/internal/mediums/BUILD index 22bcdd14..680b0061 100644 --- a/fastpair/internal/mediums/BUILD +++ b/fastpair/internal/mediums/BUILD @@ -19,11 +19,13 @@ cc_library( srcs = [ "ble.cc", "ble_v2.cc", + "bluetooth_classic.cc", "bluetooth_radio.cc", ], hdrs = [ "ble.h", "ble_v2.h", + "bluetooth_classic.h", "bluetooth_radio.h", "mediums.h", ], @@ -105,3 +107,21 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "bluetooth_classic_test", + size = "small", + srcs = [ + "bluetooth_classic_test.cc", + ], + shard_count = 16, + deps = [ + ":mediums", + "//internal/platform:comm", + "//internal/platform:test_util", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/internal/mediums/ble.h b/fastpair/internal/mediums/ble.h index c6923384..dd40e56f 100644 --- a/fastpair/internal/mediums/ble.h +++ b/fastpair/internal/mediums/ble.h @@ -54,7 +54,7 @@ class Ble { bool IsScanning() ABSL_LOCKS_EXCLUDED(mutex_); // Return BleMedium - BleMedium& getMedium() { return medium_; } + BleMedium& GetMedium() { return medium_; } private: // Same as IsAvailable(), but must be called with mutex_ held. diff --git a/fastpair/internal/mediums/ble_test.cc b/fastpair/internal/mediums/ble_test.cc index 9fb93fd1..0c2b7738 100644 --- a/fastpair/internal/mediums/ble_test.cc +++ b/fastpair/internal/mediums/ble_test.cc @@ -50,7 +50,7 @@ TEST(BleTest, CanStartDiscovery) { std::string fast_pair_service_uuid(kFastPairServiceUuid); CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); - ble_b.getMedium().StartAdvertising(service_id, advertisement_bytes, + ble_b.GetMedium().StartAdvertising(service_id, advertisement_bytes, fast_pair_service_uuid); EXPECT_TRUE(ble_a.StartScanning( @@ -69,7 +69,7 @@ TEST(BleTest, CanStartDiscovery) { })); EXPECT_TRUE(ble_a.IsScanning()); EXPECT_TRUE(accept_latch.Await(kWaitDuration).result()); - ble_b.getMedium().StopAdvertising(service_id); + ble_b.GetMedium().StopAdvertising(service_id); EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); EXPECT_TRUE(ble_a.StopScanning(service_id)); EXPECT_FALSE(ble_a.IsScanning()); diff --git a/fastpair/internal/mediums/bluetooth_classic.cc b/fastpair/internal/mediums/bluetooth_classic.cc new file mode 100644 index 00000000..3ad15854 --- /dev/null +++ b/fastpair/internal/mediums/bluetooth_classic.cc @@ -0,0 +1,64 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastpair/internal/mediums/bluetooth_classic.h" + +#include +#include + +#include "absl/strings/escaping.h" +#include "internal/platform/bluetooth_adapter.h" + +namespace nearby { +namespace fastpair { + +BluetoothClassic::BluetoothClassic(BluetoothRadio& radio) : radio_(radio) {} + +bool BluetoothClassic::IsAvailable() const { + MutexLock lock(&mutex_); + return IsAvailableLocked(); +} + +bool BluetoothClassic::IsAvailableLocked() const { + return medium_.IsValid() && adapter_.IsValid() && adapter_.IsEnabled(); +} + +std::unique_ptr BluetoothClassic::CreatePairing( + absl::string_view public_address) { + MutexLock lock(&mutex_); + if (!radio_.IsEnabled()) { + NEARBY_LOGS(INFO) + << __func__ + << "Can't create bluetooth pairing because Bluetooth was NOT enabled"; + return nullptr; + } + if (!IsAvailableLocked()) { + NEARBY_LOGS(VERBOSE) << __func__ + << "Can't create bluetooth pairing because " + "BluetoothClassic isn't available."; + return nullptr; + } + BluetoothDevice device = medium_.GetRemoteDevice(std::string(public_address)); + if (!device.IsValid()) { + NEARBY_LOGS(INFO) << __func__ + << "Can't create bluetooth pairing because Bluetooth " + "device was NOT found"; + return nullptr; + } + return medium_.CreatePairing(device); +} + +BluetoothClassicMedium& BluetoothClassic::GetMedium() { return medium_; } +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/mediums/bluetooth_classic.h b/fastpair/internal/mediums/bluetooth_classic.h new file mode 100644 index 00000000..f04aa308 --- /dev/null +++ b/fastpair/internal/mediums/bluetooth_classic.h @@ -0,0 +1,56 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ + +#include + +#include "absl/strings/string_view.h" +#include "fastpair/internal/mediums/bluetooth_radio.h" +#include "internal/platform/bluetooth_classic.h" +#include "internal/platform/mutex.h" +namespace nearby { +namespace fastpair { + +class BluetoothClassic { + public: + explicit BluetoothClassic(BluetoothRadio& bluetooth_radio); + ~BluetoothClassic() = default; + + // Returns true, if BT communications are supported by a platform. + bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns a new BluetoothPairing instance to handle the pairing process + // with the remote device. + std::unique_ptr CreatePairing( + absl::string_view public_address); + + BluetoothClassicMedium& GetMedium() ABSL_LOCKS_EXCLUDED(mutex_); + + private: + // Same as IsAvailable(), but must be called with mutex_ held. + bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable Mutex mutex_; + BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); + BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ + radio_.GetBluetoothAdapter()}; + BluetoothClassicMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_CLASSIC_H_ diff --git a/fastpair/internal/mediums/bluetooth_classic_test.cc b/fastpair/internal/mediums/bluetooth_classic_test.cc new file mode 100644 index 00000000..b2cde5b3 --- /dev/null +++ b/fastpair/internal/mediums/bluetooth_classic_test.cc @@ -0,0 +1,89 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastpair/internal/mediums/bluetooth_classic.h" + +#include "gtest/gtest.h" +#include "absl/strings/escaping.h" +#include "internal/platform/bluetooth_adapter.h" +#include "internal/platform/medium_environment.h" + +namespace nearby { +namespace fastpair { +namespace { + +TEST(BluetoothClassicTest, CanCreatePairing) { + MediumEnvironment::Instance().Start(); + BluetoothRadio radio; + BluetoothClassic bluetooth_classic(radio); + BluetoothAdapter provider_adapter; + provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled); + BluetoothClassicMedium bt_provider(provider_adapter); + + EXPECT_TRUE(bluetooth_classic.IsAvailable()); + EXPECT_TRUE(bluetooth_classic.CreatePairing( + absl::BytesToHexString(provider_adapter.GetMacAddress()))); + MediumEnvironment::Instance().Stop(); +} + +TEST(BluetoothClassicTest, RemoteDeviceNotFound) { + MediumEnvironment::Instance().Start(); + BluetoothRadio radio; + BluetoothClassic bluetooth_classic(radio); + BluetoothAdapter provider_adapter; + provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled); + BluetoothClassicMedium bt_provider(provider_adapter); + + EXPECT_TRUE(bluetooth_classic.IsAvailable()); + EXPECT_FALSE( + bluetooth_classic.CreatePairing(absl::BytesToHexString("bleaddress"))); + MediumEnvironment::Instance().Stop(); +} + +TEST(BluetoothClassicTest, RadioDisable) { + BluetoothRadio radio; + BluetoothClassic bluetooth_classic(radio); + BluetoothAdapter provider_adapter; + provider_adapter.SetStatus(BluetoothAdapter::Status::kEnabled); + BluetoothClassicMedium bt_provider(provider_adapter); + radio.Disable(); + + EXPECT_FALSE(bluetooth_classic.IsAvailable()); + EXPECT_FALSE(bluetooth_classic.CreatePairing( + absl::BytesToHexString(provider_adapter.GetMacAddress()))); +} + +TEST(BluetoothClassicTest, BluetoothAdapterDisable) { + BluetoothRadio radio; + radio.GetBluetoothAdapter().SetStatus(BluetoothAdapter::Status::kDisabled); + BluetoothClassic bluetooth_classic(radio); + BluetoothAdapter adapter_provider; + adapter_provider.SetStatus(BluetoothAdapter::Status::kEnabled); + BluetoothClassicMedium bt_provider(adapter_provider); + + EXPECT_FALSE(bluetooth_classic.IsAvailable()); + EXPECT_FALSE(bluetooth_classic.CreatePairing( + absl::BytesToHexString(adapter_provider.GetMacAddress()))); +} + +TEST(BluetoothClassicTest, GetMedium) { + BluetoothRadio radio; + BluetoothClassic bluetooth_classic(radio); + + EXPECT_TRUE(bluetooth_classic.GetMedium().IsValid()); +} + +} // namespace +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/mediums/mediums.h b/fastpair/internal/mediums/mediums.h index cf3f21a9..f94a4eb3 100644 --- a/fastpair/internal/mediums/mediums.h +++ b/fastpair/internal/mediums/mediums.h @@ -17,6 +17,7 @@ #include "fastpair/internal/mediums/ble.h" #include "fastpair/internal/mediums/ble_v2.h" +#include "fastpair/internal/mediums/bluetooth_classic.h" #include "fastpair/internal/mediums/bluetooth_radio.h" namespace nearby { @@ -37,6 +38,8 @@ class Mediums { // Returns a handle to the Ble medium. BleV2& GetBleV2() { return ble_v2_; } + BluetoothClassic& GetBluetoothClassic() { return bluetooth_classic_; } + private: // The order of declaration is critical for both construction and // destruction. @@ -49,6 +52,7 @@ class Mediums { BluetoothRadio bluetooth_radio_; Ble ble_{bluetooth_radio_}; BleV2 ble_v2_{bluetooth_radio_}; + BluetoothClassic bluetooth_classic_{bluetooth_radio_}; }; } // namespace fastpair diff --git a/fastpair/internal/mediums/mediums_test.cc b/fastpair/internal/mediums/mediums_test.cc index 2746abb3..cee2c0ce 100644 --- a/fastpair/internal/mediums/mediums_test.cc +++ b/fastpair/internal/mediums/mediums_test.cc @@ -25,6 +25,7 @@ TEST(MediumTest, ConstructorWorks) { EXPECT_TRUE(medium.GetBluetoothRadio().IsAdapterValid()); EXPECT_FALSE(medium.GetBle().IsScanning()); EXPECT_TRUE(medium.GetBleV2().ConnectToGattServer("ble_address")); + EXPECT_TRUE(medium.GetBluetoothClassic().IsAvailable()); } } // namespace } // namespace fastpair diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc index e91d5848..e0946019 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc @@ -79,7 +79,7 @@ TEST_F(FastPairScannerImplTest, StartScanning) { std::string service_id(kServiceID); ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_2.GetBle().getMedium().StartAdvertising( + mediums_2.GetBle().GetMedium().StartAdvertising( service_id, advertisement_bytes, fast_pair_service_uuid); // Fast Pair scanner startScanning @@ -88,7 +88,7 @@ TEST_F(FastPairScannerImplTest, StartScanning) { EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); // Advertiser stopAdvertising - mediums_2.GetBle().getMedium().StopAdvertising(service_id); + mediums_2.GetBle().GetMedium().StopAdvertising(service_id); // Notify device lost EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); diff --git a/fastpair/scanning/scanner_broker_impl_test.cc b/fastpair/scanning/scanner_broker_impl_test.cc index 273dcd04..eceddd8c 100644 --- a/fastpair/scanning/scanner_broker_impl_test.cc +++ b/fastpair/scanning/scanner_broker_impl_test.cc @@ -92,7 +92,7 @@ TEST_F(ScannerBrokerImplTest, CanStartScanning) { std::string service_id(kServiceID); ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; std::string fast_pair_service_uuid(kFastPairServiceUuid); - mediums_2.GetBle().getMedium().StartAdvertising( + mediums_2.GetBle().GetMedium().StartAdvertising( service_id, advertisement_bytes, fast_pair_service_uuid); // Fast Pair scanner startScanning @@ -102,7 +102,7 @@ TEST_F(ScannerBrokerImplTest, CanStartScanning) { EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); // Advertiser stopAdvertising - mediums_2.GetBle().getMedium().StopAdvertising(service_id); + mediums_2.GetBle().GetMedium().StopAdvertising(service_id); // Notify device lost EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result());