blob: 24644d04c7682775a676377d3f27f913ce382e4f [file] [log] [blame]
// Copyright 2019 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 "ash/power/gatt_battery_poller.h"
#include "ash/power/gatt_battery_percentage_fetcher.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "device/bluetooth/bluetooth_adapter.h"
namespace ash {
namespace {
// Maximum number of consecutive attempts to try reading the battery status.
// The class stops polling if |current_retry_count_| exceeds this value.
const int kMaxRetryCount = 3;
// Default interval for polling the device battery value.
constexpr base::TimeDelta kDefaultPollInterval =
base::TimeDelta::FromMinutes(10);
GattBatteryPoller::Factory* g_test_factory_instance = nullptr;
} // namespace
// static
void GattBatteryPoller::Factory::SetFactoryForTesting(Factory* factory) {
g_test_factory_instance = factory;
}
// static
std::unique_ptr<GattBatteryPoller> GattBatteryPoller::Factory::NewInstance(
scoped_refptr<device::BluetoothAdapter> adapter,
const std::string& device_address,
std::unique_ptr<base::OneShotTimer> poll_timer) {
if (g_test_factory_instance) {
return g_test_factory_instance->BuildInstance(adapter, device_address,
std::move(poll_timer));
}
auto instance = base::WrapUnique(new GattBatteryPoller(device_address));
instance->StartFetching(adapter, std::move(poll_timer));
return instance;
}
GattBatteryPoller::GattBatteryPoller(const std::string& device_address)
: device_address_(device_address) {}
GattBatteryPoller::~GattBatteryPoller() = default;
void GattBatteryPoller::StartFetching(
scoped_refptr<device::BluetoothAdapter> adapter,
std::unique_ptr<base::OneShotTimer> poll_timer) {
adapter_ = adapter;
poll_timer_ = std::move(poll_timer);
CreateBatteryFetcher();
}
void GattBatteryPoller::CreateBatteryFetcher() {
DCHECK(!fetcher_);
// Creating the fetcher implicitly begins the process of fetching the battery
// status.
fetcher_ = GattBatteryPercentageFetcher::Factory::NewInstance(
adapter_, device_address_,
base::BindOnce(&GattBatteryPoller::OnBatteryPercentageFetched,
weak_ptr_factory_.GetWeakPtr()));
}
void GattBatteryPoller::OnBatteryPercentageFetched(
base::Optional<uint8_t> battery_percentage) {
fetcher_.reset();
if (battery_percentage) {
device::BluetoothDevice* device = adapter_->GetDevice(device_address_);
if (device)
device->SetBatteryPercentage(*battery_percentage);
}
ScheduleNextAttempt(battery_percentage.has_value());
}
void GattBatteryPoller::ScheduleNextAttempt(bool was_last_attempt_successful) {
device::BluetoothDevice* device = adapter_->GetDevice(device_address_);
// If the device is not present now, it won't be present in the future. Give
// up retrying.
if (!device)
return;
if (was_last_attempt_successful) {
current_retry_count_ = 0;
StartNextAttemptTimer();
return;
}
++current_retry_count_;
if (current_retry_count_ <= kMaxRetryCount) {
StartNextAttemptTimer();
} else {
// Reset battery field after exceeding the retry count.
device->SetBatteryPercentage(base::nullopt);
}
}
void GattBatteryPoller::StartNextAttemptTimer() {
poll_timer_->Start(FROM_HERE, kDefaultPollInterval,
base::BindOnce(&GattBatteryPoller::CreateBatteryFetcher,
weak_ptr_factory_.GetWeakPtr()));
}
} // namespace ash