blob: 2117384eaf293a29c514ad87a49a5ae6d4f00813 [file] [log] [blame]
// Copyright 2016 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 "services/ui/ws/user_activity_monitor.h"
#include "base/bind.h"
#include "base/time/default_tick_clock.h"
namespace ui {
namespace ws {
UserActivityMonitor::UserActivityMonitor(std::unique_ptr<base::TickClock> clock)
: now_clock_(std::move(clock)) {
if (!now_clock_)
now_clock_ = base::WrapUnique(new base::DefaultTickClock);
last_activity_ = now_clock_->NowTicks();
}
UserActivityMonitor::~UserActivityMonitor() {}
void UserActivityMonitor::OnUserActivity() {
base::TimeTicks now = now_clock_->NowTicks();
for (auto& pair : activity_observers_) {
ActivityObserverInfo* info = &(pair.first);
if (info->last_activity_notification.is_null() ||
(now - info->last_activity_notification) > info->delay) {
pair.second->OnUserActivity();
info->last_activity_notification = now;
}
}
// Wake up all the 'idle' observers.
for (auto& pair : idle_observers_) {
IdleObserverInfo* info = &(pair.first);
if (info->idle_state == mojom::UserIdleObserver::IdleState::ACTIVE)
continue;
info->last_idle_state_notification = now;
info->idle_state = mojom::UserIdleObserver::IdleState::ACTIVE;
pair.second->OnUserIdleStateChanged(info->idle_state);
}
last_activity_ = now;
// Start the timer if there are some idle observers.
if (idle_timer_.IsRunning())
idle_timer_.Reset();
}
void UserActivityMonitor::Add(mojom::UserActivityMonitorRequest request) {
bindings_.AddBinding(this, std::move(request));
}
void UserActivityMonitor::AddUserActivityObserver(
uint32_t delay_between_notify_secs,
mojom::UserActivityObserverPtr observer) {
ActivityObserverInfo info;
info.delay = base::TimeDelta::FromSeconds(delay_between_notify_secs);
observer.set_connection_error_handler(
base::Bind(&UserActivityMonitor::OnActivityObserverDisconnected,
base::Unretained(this), observer.get()));
activity_observers_.push_back(std::make_pair(info, std::move(observer)));
}
void UserActivityMonitor::AddUserIdleObserver(
uint32_t idleness_in_minutes,
mojom::UserIdleObserverPtr observer) {
IdleObserverInfo info;
info.idle_duration = base::TimeDelta::FromMinutes(idleness_in_minutes);
base::TimeTicks now = now_clock_->NowTicks();
DCHECK(!last_activity_.is_null());
bool user_is_active = (now - last_activity_ < info.idle_duration);
info.idle_state = user_is_active ? mojom::UserIdleObserver::IdleState::ACTIVE
: mojom::UserIdleObserver::IdleState::IDLE;
info.last_idle_state_notification = now;
observer->OnUserIdleStateChanged(info.idle_state);
observer.set_connection_error_handler(
base::Bind(&UserActivityMonitor::OnIdleObserverDisconnected,
base::Unretained(this), observer.get()));
idle_observers_.push_back(std::make_pair(info, std::move(observer)));
if (user_is_active)
ActivateIdleTimer();
}
void UserActivityMonitor::ActivateIdleTimer() {
if (idle_timer_.IsRunning())
return;
idle_timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(1), this,
&UserActivityMonitor::OnMinuteTimer);
}
void UserActivityMonitor::OnMinuteTimer() {
base::TimeTicks now = now_clock_->NowTicks();
bool active_observer = false;
for (auto& pair : idle_observers_) {
IdleObserverInfo* info = &(pair.first);
if (info->idle_state == mojom::UserIdleObserver::IdleState::IDLE)
continue;
if (now - info->last_idle_state_notification < info->idle_duration) {
active_observer = true;
continue;
}
info->last_idle_state_notification = now;
info->idle_state = mojom::UserIdleObserver::IdleState::IDLE;
pair.second->OnUserIdleStateChanged(info->idle_state);
}
// All observers are already notified of IDLE. No point running the timer
// anymore.
if (!active_observer)
idle_timer_.Stop();
}
void UserActivityMonitor::OnActivityObserverDisconnected(
mojom::UserActivityObserver* observer) {
activity_observers_.erase(std::remove_if(
activity_observers_.begin(), activity_observers_.end(),
[observer](const std::pair<ActivityObserverInfo,
mojom::UserActivityObserverPtr>& pair) {
return pair.second.get() == observer;
}));
}
void UserActivityMonitor::OnIdleObserverDisconnected(
mojom::UserIdleObserver* observer) {
idle_observers_.erase(std::remove_if(
idle_observers_.begin(), idle_observers_.end(),
[observer](
const std::pair<IdleObserverInfo, mojom::UserIdleObserverPtr>& pair) {
return pair.second.get() == observer;
}));
}
} // namespace ws
} // namespace ui