Files
nearby/cpp/core/internal/mediums/bluetooth_radio.cc
T
Alexey Polyudov 204f76077d nearby: snapshot as of cl/296436629
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
Change-Id: I2cf5bf225b76f4c1541954651f3a7544a14e0cec
2020-04-04 12:52:31 -07:00

123 lines
3.3 KiB
C++

#include "core/internal/mediums/bluetooth_radio.h"
#include "platform/exception.h"
namespace location {
namespace nearby {
namespace connections {
template <typename Platform>
std::int64_t BluetoothRadio<Platform>::kPauseBetweenToggleDurationMillis = 3000;
template <typename Platform>
BluetoothRadio<Platform>::BluetoothRadio()
: bluetooth_adapter_(Platform::createBluetoothAdapter()),
thread_utils_(Platform::createThreadUtils()),
originally_enabled_() {
if (bluetooth_adapter_.isNull()) {
// TODO(reznor): log.atSevere().log("Failed to retrieve default
// BluetoothAdapter, Bluetooth is unsupported.");
}
}
template <typename Platform>
BluetoothRadio<Platform>::~BluetoothRadio() {
// We never enabled Bluetooth, nothing to do.
if (originally_enabled_.isNull()) {
return;
}
// Make sure we cleanup the one non-ScopedPtr member before we leave the
// destructor.
ScopedPtr<Ptr<AtomicBoolean> > scoped_originally_enabled(originally_enabled_);
// Toggle Bluetooth regardless of our original state. Some devices/chips can
// start to freak out after some time (e.g. b/37775337), and this helps to
// ensure BT resets properly.
toggle();
if (!setBluetoothState(originally_enabled_->get())) {
// TODO(reznor): log.atWarning().log("Failed to turn Bluetooth back to its
// original state.");
}
}
template <typename Platform>
bool BluetoothRadio<Platform>::enable() {
if (!saveOriginalState()) {
return false;
}
return setBluetoothState(true);
}
template <typename Platform>
bool BluetoothRadio<Platform>::disable() {
if (!saveOriginalState()) {
return false;
}
return setBluetoothState(false);
}
template <typename Platform>
bool BluetoothRadio<Platform>::isEnabled() {
return !bluetooth_adapter_.isNull() && isInDesiredState(true);
}
template <typename Platform>
void BluetoothRadio<Platform>::toggle() {
if (!saveOriginalState()) {
return;
}
if (!setBluetoothState(false)) {
// TODO(reznor): log.atWarning().log("Failed to turn Bluetooth off while
// toggling state.");
}
if (Exception::INTERRUPTED ==
thread_utils_->sleep(kPauseBetweenToggleDurationMillis)) {
// TODO(reznor): log.atSevere().withCause(e).log("Interrupted while waiting
// in between a Bluetooth toggle.");
return;
}
if (!setBluetoothState(true)) {
// TODO(reznor): log.atWarning().log("Failed to turn Bluetooth on while
// toggling state.");
}
}
template <typename Platform>
bool BluetoothRadio<Platform>::setBluetoothState(bool enable) {
return bluetooth_adapter_->setStatus(
enable ? BluetoothAdapter::Status::ENABLED
: BluetoothAdapter::Status::DISABLED);
}
template <typename Platform>
bool BluetoothRadio<Platform>::isInDesiredState(bool should_be_enabled) const {
return ((should_be_enabled && bluetooth_adapter_->isEnabled()) ||
(!should_be_enabled && !bluetooth_adapter_->isEnabled()));
}
template <typename Platform>
bool BluetoothRadio<Platform>::saveOriginalState() {
if (bluetooth_adapter_.isNull()) {
return false;
}
// If we haven't saved the original state of the radio, save it.
if (originally_enabled_.isNull()) {
originally_enabled_ =
Platform::createAtomicBoolean(bluetooth_adapter_->isEnabled());
}
return true;
}
} // namespace connections
} // namespace nearby
} // namespace location