chromium/chrome/browser/ash/crosapi/idle_service_ash.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/crosapi/idle_service_ash.h"

#include <stdint.h>

#include "base/logging.h"
#include "chromeos/dbus/power/power_policy_controller.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/events/event.h"

namespace crosapi {

namespace {

// Minimal intervals between successive UserActivity events to trigger dispatch
// in IdleServiceAsh::Dispatcher.
constexpr int64_t kUserActivityDispatchIntervalMs = 1000;

}  // namespace

/******** IdleServiceAsh::Dispatcher ********/

IdleServiceAsh::Dispatcher::Dispatcher() {
  if (!IdleServiceAsh::Dispatcher::is_disabled_for_testing_) {
    CHECK(ui::UserActivityDetector::Get());
    CHECK(ash::SessionManagerClient::Get());
    ui::UserActivityDetector::Get()->AddObserver(this);
    ash::SessionManagerClient::Get()->AddObserver(this);
  }
}

IdleServiceAsh::Dispatcher::~Dispatcher() {
  if (!IdleServiceAsh::Dispatcher::is_disabled_for_testing_) {
    ash::SessionManagerClient::Get()->RemoveObserver(this);
    ui::UserActivityDetector::Get()->RemoveObserver(this);
  }
}

void IdleServiceAsh::Dispatcher::OnUserActivity(const ui::Event* event) {
  base::TimeTicks event_time =
      event ? event->time_stamp() : base::TimeTicks::Now();
  // UserActivityDetector already limits event frequency, but apply even more
  // limit to prevent incessant calls to DispatchChange().
  if (last_user_activity_time_stamp_.is_null() ||
      (event_time - last_user_activity_time_stamp_).InMilliseconds() >=
          kUserActivityDispatchIntervalMs) {
    last_user_activity_time_stamp_ = event_time;
    DispatchChange();
  }
}

void IdleServiceAsh::Dispatcher::ScreenLockedStateUpdated() {
  DispatchChange();
}

void IdleServiceAsh::Dispatcher::DispatchChange() {
  mojom::IdleInfoPtr idle_info = IdleServiceAsh::ReadIdleInfoFromSystem();
  for (auto& observer : observers_) {
    mojom::IdleInfoPtr idle_info_copy = idle_info->Clone();
    observer->OnIdleInfoChanged(std::move(idle_info_copy));
  }
}

// static
bool IdleServiceAsh::Dispatcher::is_disabled_for_testing_ = false;

/******** IdleServiceAsh ********/

// static
mojom::IdleInfoPtr IdleServiceAsh::ReadIdleInfoFromSystem() {
  mojom::IdleInfoPtr idle_info = mojom::IdleInfo::New();

  if (!IdleServiceAsh::Dispatcher::is_disabled_for_testing_) {
    // Taken from extensions::IdleManager::GetAutoLockDelay().
    idle_info->auto_lock_delay = chromeos::PowerPolicyController::Get()
                                     ->GetMaxPolicyAutoScreenLockDelay();

    // Taken from ui::CalculateIdleTime() for ChromeOS (partial).
    idle_info->last_activity_time =
        ui::UserActivityDetector::Get()->last_activity_time();

    // Taken from ui::CheckIdleStateIsLocked() for ChromeOS.
    idle_info->is_locked = ash::SessionManagerClient::Get()->IsScreenLocked();
  }

  return idle_info;
}

// static
void IdleServiceAsh::DisableForTesting() {
  IdleServiceAsh::Dispatcher::is_disabled_for_testing_ = true;
}

IdleServiceAsh::IdleServiceAsh() = default;

IdleServiceAsh::~IdleServiceAsh() = default;

void IdleServiceAsh::BindReceiver(
    mojo::PendingReceiver<mojom::IdleService> receiver) {
  receivers_.Add(this, std::move(receiver));
}

void IdleServiceAsh::AddIdleInfoObserver(
    mojo::PendingRemote<mojom::IdleInfoObserver> observer) {
  // Fire the observer with the initial value.
  mojo::Remote<mojom::IdleInfoObserver> remote(std::move(observer));
  remote->OnIdleInfoChanged(ReadIdleInfoFromSystem());

  dispatcher_.observers_.Add(std::move(remote));
}

}  // namespace crosapi