blob: 637de87fbd3db68675afe5821abead8225845312 [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 "chrome/browser/ash/child_accounts/time_limits/app_types.h"
#include <algorithm>
#include "base/check_op.h"
#include "base/notreached.h"
namespace ash {
namespace app_time {
namespace {
std::string AppTypeToString(apps::mojom::AppType app_type) {
switch (app_type) {
case apps::mojom::AppType::kUnknown:
return "Unknown";
case apps::mojom::AppType::kArc:
return "Arc";
case apps::mojom::AppType::kWeb:
return "Web";
case apps::mojom::AppType::kExtension:
case apps::mojom::AppType::kStandaloneBrowserExtension:
return "Extension";
case apps::mojom::AppType::kBuiltIn:
return "Built in";
case apps::mojom::AppType::kCrostini:
return "Crostini";
case apps::mojom::AppType::kMacOs:
return "Mac OS";
case apps::mojom::AppType::kPluginVm:
return "Plugin VM";
case apps::mojom::AppType::kStandaloneBrowser:
return "LaCrOS";
case apps::mojom::AppType::kRemote:
return "Remote";
case apps::mojom::AppType::kBorealis:
return "Borealis";
case apps::mojom::AppType::kSystemWeb:
return "SystemWeb";
}
NOTREACHED();
}
// static
bool CanMerge(const AppActivity::ActiveTime& t1,
const AppActivity::ActiveTime& t2) {
if (t1.active_from() <= t2.active_from() &&
t1.active_to() >=
t2.active_from() -
AppActivity::ActiveTime::kActiveTimeMergePrecision) {
return true;
}
if (t2.active_from() <= t1.active_from() &&
t2.active_to() >=
t1.active_from() -
AppActivity::ActiveTime::kActiveTimeMergePrecision) {
return true;
}
return false;
}
} // namespace
AppId::AppId(apps::mojom::AppType app_type, const std::string& app_id)
: app_type_(app_type), app_id_(app_id) {
DCHECK(!app_id.empty());
}
AppId::AppId(const AppId&) = default;
AppId& AppId::operator=(const AppId&) = default;
AppId::AppId(AppId&&) = default;
AppId& AppId::operator=(AppId&&) = default;
AppId::~AppId() = default;
bool AppId::operator==(const AppId& rhs) const {
return app_type_ == rhs.app_type() && app_id_ == rhs.app_id();
}
bool AppId::operator!=(const AppId& rhs) const {
return !(*this == rhs);
}
bool AppId::operator<(const AppId& rhs) const {
return app_id_ < rhs.app_id();
}
std::ostream& operator<<(std::ostream& out, const AppId& id) {
return out << " [" << AppTypeToString(id.app_type()) << " : " << id.app_id()
<< "]";
}
PauseAppInfo::PauseAppInfo(const AppId& app,
base::TimeDelta limit,
bool show_dialog)
: app_id(app), daily_limit(limit), show_pause_dialog(show_dialog) {}
AppLimit::AppLimit(AppRestriction restriction,
absl::optional<base::TimeDelta> daily_limit,
base::Time last_updated)
: restriction_(restriction),
daily_limit_(daily_limit),
last_updated_(last_updated) {
DCHECK_EQ(restriction_ == AppRestriction::kBlocked,
daily_limit_ == absl::nullopt);
DCHECK(daily_limit_ == absl::nullopt ||
daily_limit >= base::TimeDelta::FromHours(0));
DCHECK(daily_limit_ == absl::nullopt ||
daily_limit <= base::TimeDelta::FromHours(24));
}
AppLimit::AppLimit(const AppLimit&) = default;
AppLimit& AppLimit::operator=(const AppLimit&) = default;
AppLimit::AppLimit(AppLimit&&) = default;
AppLimit& AppLimit::operator=(AppLimit&&) = default;
AppLimit::~AppLimit() = default;
// static
absl::optional<AppActivity::ActiveTime> AppActivity::ActiveTime::Merge(
const ActiveTime& t1,
const ActiveTime& t2) {
if (!CanMerge(t1, t2))
return absl::nullopt;
base::Time active_from = std::min(t1.active_from(), t2.active_from());
base::Time active_to = std::max(t1.active_to(), t2.active_to());
return AppActivity::ActiveTime(active_from, active_to);
}
// static
const base::TimeDelta AppActivity::ActiveTime::kActiveTimeMergePrecision =
base::TimeDelta::FromSeconds(1);
AppActivity::ActiveTime::ActiveTime(base::Time start, base::Time end)
: active_from_(start), active_to_(end) {
DCHECK_GT(active_to_, active_from_);
}
AppActivity::ActiveTime::ActiveTime(const AppActivity::ActiveTime& rhs) =
default;
AppActivity::ActiveTime& AppActivity::ActiveTime::operator=(
const AppActivity::ActiveTime& rhs) = default;
bool AppActivity::ActiveTime::operator==(const ActiveTime& rhs) const {
return active_from_ == rhs.active_from() && active_to_ == rhs.active_to();
}
bool AppActivity::ActiveTime::operator!=(const ActiveTime& rhs) const {
return !(*this == rhs);
}
bool AppActivity::ActiveTime::Contains(base::Time timestamp) const {
return active_from_ < timestamp && active_to_ > timestamp;
}
bool AppActivity::ActiveTime::IsEarlierThan(base::Time timestamp) const {
return active_to_ <= timestamp;
}
bool AppActivity::ActiveTime::IsLaterThan(base::Time timestamp) const {
return active_from_ >= timestamp;
}
void AppActivity::ActiveTime::set_active_from(base::Time active_from) {
DCHECK_GT(active_to_, active_from);
active_from_ = active_from;
}
void AppActivity::ActiveTime::set_active_to(base::Time active_to) {
DCHECK_GT(active_to, active_from_);
active_to_ = active_to;
}
AppActivity::AppActivity(AppState app_state)
: app_state_(app_state),
running_active_time_(base::TimeDelta::FromSeconds(0)),
last_updated_time_ticks_(base::TimeTicks::Now()) {}
AppActivity::AppActivity(AppState app_state,
base::TimeDelta running_active_time)
: app_state_(app_state),
running_active_time_(running_active_time),
last_updated_time_ticks_(base::TimeTicks::Now()) {}
AppActivity::AppActivity(const AppActivity&) = default;
AppActivity& AppActivity::operator=(const AppActivity&) = default;
AppActivity::AppActivity(AppActivity&&) = default;
AppActivity& AppActivity::operator=(AppActivity&&) = default;
AppActivity::~AppActivity() = default;
void AppActivity::SetAppState(AppState app_state) {
app_state_ = app_state;
CaptureOngoingActivity(base::Time::Now());
if (!is_active_)
last_updated_time_ticks_ = base::TimeTicks::Now();
}
void AppActivity::SetAppActive(base::Time timestamp) {
DCHECK(!is_active_);
DCHECK(app_state_ == AppState::kAvailable ||
app_state_ == AppState::kAlwaysAvailable);
is_active_ = true;
last_updated_time_ticks_ = base::TimeTicks::Now();
}
void AppActivity::SetAppInactive(base::Time timestamp) {
if (!is_active_)
return;
CaptureOngoingActivity(timestamp);
is_active_ = false;
}
void AppActivity::ResetRunningActiveTime(base::Time timestamp) {
CaptureOngoingActivity(timestamp);
running_active_time_ = base::TimeDelta::FromMinutes(0);
}
base::TimeDelta AppActivity::RunningActiveTime() const {
if (!is_active_)
return running_active_time_;
return running_active_time_ +
(base::TimeTicks::Now() - last_updated_time_ticks_);
}
void AppActivity::CaptureOngoingActivity(base::Time timestamp) {
if (!is_active_)
return;
// Log the active time before the until the reset.
base::TimeTicks now = base::TimeTicks::Now();
base::TimeDelta active_time = now - last_updated_time_ticks_;
// Update |running_active_time_|.
running_active_time_ += active_time;
base::Time start_time = timestamp - active_time;
// Timestamps can be equal if SetAppInactive() is called directly after
// SetAppState(). Happens in tests.
DCHECK_GE(timestamp, start_time);
if (timestamp > start_time)
active_times_.push_back(ActiveTime(start_time, timestamp));
last_updated_time_ticks_ = now;
}
std::vector<AppActivity::ActiveTime> AppActivity::TakeActiveTimes() {
return std::move(active_times_);
}
} // namespace app_time
} // namespace ash