| // Copyright (c) 2012 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_adapter_factory.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/no_destructor.h" |
| #include "build/build_config.h" |
| #include "device/bluetooth/bluetooth_adapter.h" |
| |
| #if BUILDFLAG(IS_MAC) |
| #include "base/mac/mac_util.h" |
| #endif |
| #if BUILDFLAG(IS_WIN) |
| #include "base/win/windows_version.h" |
| #include "device/bluetooth/bluetooth_adapter_win.h" |
| #endif |
| |
| namespace device { |
| |
| BluetoothAdapterFactory::BluetoothAdapterFactory() = default; |
| |
| BluetoothAdapterFactory::~BluetoothAdapterFactory() = default; |
| |
| // static |
| BluetoothAdapterFactory* BluetoothAdapterFactory::Get() { |
| static base::NoDestructor<BluetoothAdapterFactory> factory; |
| return factory.get(); |
| } |
| |
| // static |
| bool BluetoothAdapterFactory::IsBluetoothSupported() { |
| // SetAdapterForTesting() may be used to provide a test or mock adapter |
| // instance even on platforms that would otherwise not support it. |
| if (Get()->adapter_) |
| return true; |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| bool BluetoothAdapterFactory::IsLowEnergySupported() { |
| if (values_for_testing_) { |
| return values_for_testing_->GetLESupported(); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_MAC) |
| return true; |
| #elif BUILDFLAG(IS_WIN) |
| // Windows 8 supports Low Energy GATT operations but it does not support |
| // scanning, initiating connections and GATT Server. To keep the API |
| // consistent we consider Windows 8 as lacking Low Energy support. |
| return base::win::GetVersion() >= base::win::Version::WIN10; |
| #else |
| return false; |
| #endif |
| } |
| |
| void BluetoothAdapterFactory::GetAdapter(AdapterCallback callback) { |
| DCHECK(IsBluetoothSupported()); |
| |
| if (!adapter_) { |
| adapter_callbacks_.push_back(std::move(callback)); |
| |
| adapter_under_initialization_ = BluetoothAdapter::CreateAdapter(); |
| adapter_ = adapter_under_initialization_->GetWeakPtr(); |
| adapter_->Initialize(base::BindOnce( |
| &BluetoothAdapterFactory::AdapterInitialized, base::Unretained(this))); |
| return; |
| } |
| |
| if (!adapter_->IsInitialized()) { |
| adapter_callbacks_.push_back(std::move(callback)); |
| return; |
| } |
| |
| std::move(callback).Run(scoped_refptr<BluetoothAdapter>(adapter_.get())); |
| } |
| |
| void BluetoothAdapterFactory::GetClassicAdapter(AdapterCallback callback) { |
| #if BUILDFLAG(IS_WIN) |
| DCHECK(IsBluetoothSupported()); |
| |
| if (base::win::GetVersion() < base::win::Version::WIN10) { |
| // Prior to Win10, the default adapter will support Bluetooth classic. |
| GetAdapter(std::move(callback)); |
| return; |
| } |
| |
| if (!classic_adapter_) { |
| classic_adapter_callbacks_.push_back(std::move(callback)); |
| |
| classic_adapter_under_initialization_ = |
| BluetoothAdapterWin::CreateClassicAdapter(); |
| classic_adapter_ = classic_adapter_under_initialization_->GetWeakPtr(); |
| classic_adapter_->Initialize( |
| base::BindOnce(&BluetoothAdapterFactory::ClassicAdapterInitialized, |
| base::Unretained(this))); |
| return; |
| } |
| |
| if (!classic_adapter_->IsInitialized()) { |
| classic_adapter_callbacks_.push_back(std::move(callback)); |
| return; |
| } |
| |
| std::move(callback).Run( |
| scoped_refptr<BluetoothAdapter>(classic_adapter_.get())); |
| #else |
| GetAdapter(std::move(callback)); |
| #endif // BUILDFLAG(IS_WIN) |
| } |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| // static |
| void BluetoothAdapterFactory::Shutdown() { |
| if (Get()->adapter_) |
| Get()->adapter_->Shutdown(); |
| } |
| #endif |
| |
| // static |
| void BluetoothAdapterFactory::SetAdapterForTesting( |
| scoped_refptr<BluetoothAdapter> adapter) { |
| Get()->adapter_ = adapter->GetWeakPtrForTesting(); |
| if (!adapter->IsInitialized()) |
| Get()->adapter_under_initialization_ = adapter; |
| #if BUILDFLAG(IS_WIN) |
| Get()->classic_adapter_ = adapter->GetWeakPtrForTesting(); |
| #endif |
| } |
| |
| // static |
| bool BluetoothAdapterFactory::HasSharedInstanceForTesting() { |
| return Get()->adapter_ != nullptr; |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // static |
| void BluetoothAdapterFactory::SetBleScanParserCallback( |
| BleScanParserCallback callback) { |
| Get()->ble_scan_parser_ = callback; |
| } |
| |
| // static |
| BluetoothAdapterFactory::BleScanParserCallback |
| BluetoothAdapterFactory::GetBleScanParserCallback() { |
| return Get()->ble_scan_parser_; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| BluetoothAdapterFactory::GlobalValuesForTesting::GlobalValuesForTesting() = |
| default; |
| |
| BluetoothAdapterFactory::GlobalValuesForTesting::~GlobalValuesForTesting() = |
| default; |
| |
| base::WeakPtr<BluetoothAdapterFactory::GlobalValuesForTesting> |
| BluetoothAdapterFactory::GlobalValuesForTesting::GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| std::unique_ptr<BluetoothAdapterFactory::GlobalValuesForTesting> |
| BluetoothAdapterFactory::InitGlobalValuesForTesting() { |
| auto v = std::make_unique<BluetoothAdapterFactory::GlobalValuesForTesting>(); |
| values_for_testing_ = v->GetWeakPtr(); |
| return v; |
| } |
| |
| void BluetoothAdapterFactory::AdapterInitialized() { |
| DCHECK(adapter_); |
| DCHECK(adapter_under_initialization_); |
| |
| // Move |adapter_under_initialization_| and |adapter_callbacks_| to avoid |
| // potential re-entrancy issues while looping over the callbacks. |
| scoped_refptr<BluetoothAdapter> adapter = |
| std::move(adapter_under_initialization_); |
| std::vector<AdapterCallback> callbacks = std::move(adapter_callbacks_); |
| for (auto& callback : callbacks) |
| std::move(callback).Run(adapter); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| void BluetoothAdapterFactory::ClassicAdapterInitialized() { |
| DCHECK(classic_adapter_); |
| DCHECK(classic_adapter_under_initialization_); |
| |
| // Move |adapter_under_initialization_| and |adapter_callbacks_| to avoid |
| // potential re-entrancy issues while looping over the callbacks. |
| scoped_refptr<BluetoothAdapter> adapter = |
| std::move(classic_adapter_under_initialization_); |
| std::vector<AdapterCallback> callbacks = |
| std::move(classic_adapter_callbacks_); |
| for (auto& callback : callbacks) |
| std::move(callback).Run(adapter); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| } // namespace device |