#include "services/device/public/cpp/test/test_wake_lock_provider.h"
#include <memory>
#include <utility>
#include "base/check_op.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/notimplemented.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote_set.h"
namespace device {
class TestWakeLockProvider::TestWakeLock : public mojom::WakeLock {
public:
TestWakeLock(mojo::PendingReceiver<mojom::WakeLock> receiver,
mojom::WakeLockType type,
TestWakeLockProvider* provider)
: type_(type), provider_(provider) {
AddClient(std::move(receiver));
receivers_.set_disconnect_handler(base::BindRepeating(
&TestWakeLock::OnConnectionError, base::Unretained(this)));
}
TestWakeLock(const TestWakeLock&) = delete;
TestWakeLock& operator=(const TestWakeLock&) = delete;
~TestWakeLock() override = default;
mojom::WakeLockType type() const { return type_; }
void RequestWakeLock() override {
DCHECK(receivers_.current_context());
DCHECK_GE(num_lock_requests_, 0);
if (*receivers_.current_context())
return;
*receivers_.current_context() = true;
num_lock_requests_++;
CheckAndNotifyProvider();
}
void CancelWakeLock() override {
DCHECK(receivers_.current_context());
if (!(*receivers_.current_context()))
return;
DCHECK_GT(num_lock_requests_, 0);
*receivers_.current_context() = false;
num_lock_requests_--;
CheckAndNotifyProvider();
}
void AddClient(mojo::PendingReceiver<mojom::WakeLock> receiver) override {
receivers_.Add(this, std::move(receiver), std::make_unique<bool>(false));
}
void ChangeType(mojom::WakeLockType type,
ChangeTypeCallback callback) override {
NOTIMPLEMENTED();
}
void HasWakeLockForTests(HasWakeLockForTestsCallback callback) override {
NOTIMPLEMENTED();
}
void OnConnectionError() {
DCHECK(receivers_.current_context());
if (*receivers_.current_context() && num_lock_requests_ > 0) {
num_lock_requests_--;
CheckAndNotifyProvider();
}
if (receivers_.empty())
provider_->OnConnectionError(type_, this);
}
private:
void CheckAndNotifyProvider() {
if (num_lock_requests_ == 1) {
provider_->OnWakeLockActivated(type_);
return;
}
if (num_lock_requests_ == 0) {
provider_->OnWakeLockDeactivated(type_);
return;
}
}
mojom::WakeLockType type_;
raw_ptr<TestWakeLockProvider> provider_;
mojo::ReceiverSet<mojom::WakeLock, std::unique_ptr<bool>> receivers_;
int num_lock_requests_ = 0;
};
struct TestWakeLockProvider::WakeLockDataPerType {
WakeLockDataPerType() = default;
WakeLockDataPerType(const WakeLockDataPerType&) = delete;
WakeLockDataPerType& operator=(const WakeLockDataPerType&) = delete;
~WakeLockDataPerType() = default;
int64_t count = 0;
std::map<TestWakeLock*, std::unique_ptr<TestWakeLock>> wake_locks;
mojo::RemoteSet<mojom::WakeLockObserver> observers;
};
TestWakeLockProvider::TestWakeLockProvider() {
wake_lock_store_[mojom::WakeLockType::kPreventAppSuspension] =
std::make_unique<WakeLockDataPerType>();
wake_lock_store_[mojom::WakeLockType::kPreventDisplaySleep] =
std::make_unique<WakeLockDataPerType>();
wake_lock_store_[mojom::WakeLockType::kPreventDisplaySleepAllowDimming] =
std::make_unique<WakeLockDataPerType>();
}
TestWakeLockProvider::~TestWakeLockProvider() = default;
void TestWakeLockProvider::BindReceiver(
mojo::PendingReceiver<mojom::WakeLockProvider> receiver) {
receivers_.Add(this, std::move(receiver));
}
void TestWakeLockProvider::GetWakeLockContextForID(
int context_id,
mojo::PendingReceiver<mojom::WakeLockContext> receiver) {
NOTIMPLEMENTED();
}
void TestWakeLockProvider::GetWakeLockWithoutContext(
mojom::WakeLockType type,
mojom::WakeLockReason reason,
const std::string& description,
mojo::PendingReceiver<mojom::WakeLock> receiver) {
auto wake_lock =
std::make_unique<TestWakeLock>(std::move(receiver), type, this);
GetWakeLockDataPerType(type).wake_locks[wake_lock.get()] =
std::move(wake_lock);
}
void TestWakeLockProvider::OnConnectionError(mojom::WakeLockType type,
TestWakeLock* wake_lock) {
size_t result = GetWakeLockDataPerType(type).wake_locks.erase(wake_lock);
DCHECK_GT(result, 0UL);
}
TestWakeLockProvider::WakeLockDataPerType&
TestWakeLockProvider::GetWakeLockDataPerType(mojom::WakeLockType type) const {
auto it = wake_lock_store_.find(type);
CHECK(it != wake_lock_store_.end());
return *(it->second);
}
void TestWakeLockProvider::OnWakeLockActivated(mojom::WakeLockType type) {
const int64_t old_count = GetWakeLockDataPerType(type).count;
DCHECK_GE(old_count, 0);
GetWakeLockDataPerType(type).count = old_count + 1;
}
void TestWakeLockProvider::OnWakeLockDeactivated(mojom::WakeLockType type) {
const int64_t old_count = GetWakeLockDataPerType(type).count;
DCHECK_GT(old_count, 0);
const int64_t new_count = old_count - 1;
GetWakeLockDataPerType(type).count = new_count;
if (new_count == 0) {
for (auto& observer : GetWakeLockDataPerType(type).observers)
observer->OnWakeLockDeactivated(type);
}
}
void TestWakeLockProvider::NotifyOnWakeLockDeactivation(
mojom::WakeLockType type,
mojo::PendingRemote<mojom::WakeLockObserver> pending_observer) {
mojo::Remote<mojom::WakeLockObserver> observer(std::move(pending_observer));
if (GetWakeLockDataPerType(type).count == 0) {
observer->OnWakeLockDeactivated(type);
}
GetWakeLockDataPerType(type).observers.Add(std::move(observer));
}
void TestWakeLockProvider::GetActiveWakeLocksForTests(
mojom::WakeLockType type,
GetActiveWakeLocksForTestsCallback callback) {
std::move(callback).Run(GetWakeLockDataPerType(type).count);
}
}