chromium/chrome/browser/ash/child_accounts/child_user_service.cc

// Copyright 2019 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/child_accounts/child_user_service.h"

#include "base/check.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/ash/child_accounts/time_limits/app_activity_registry.h"
#include "chrome/browser/ash/child_accounts/time_limits/app_time_controller.h"
#include "chrome/browser/ash/child_accounts/time_limits/app_types.h"
#include "chrome/browser/ash/child_accounts/usage_time_limit_processor.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/app_constants/constants.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#include "url/gurl.h"

namespace ash {

namespace {
// UMA histogram FamilyUser.TimeLimitPolicyTypes
// Reports TimeLimitPolicyType which indicates what time limit policies
// are enabled for current Family Link user. Could report multiple buckets if
// multiple policies are enabled.
constexpr char kTimeLimitPolicyTypesHistogramName[] =
    "FamilyUser.TimeLimitPolicyTypes";

ChildUserService::TimeLimitPolicyType GetTimeLimitPolicyType(
    usage_time_limit::PolicyType policy_type) {
  ChildUserService::TimeLimitPolicyType time_limit_policy;
  switch (policy_type) {
    case usage_time_limit::PolicyType::kFixedLimit:
      time_limit_policy = ChildUserService::TimeLimitPolicyType::kBedTimeLimit;
      break;
    case usage_time_limit::PolicyType::kUsageLimit:
      time_limit_policy =
          ChildUserService::TimeLimitPolicyType::kScreenTimeLimit;
      break;
    case usage_time_limit::PolicyType::kOverride:
      time_limit_policy =
          ChildUserService::TimeLimitPolicyType::kOverrideTimeLimit;
      break;
    case usage_time_limit::PolicyType::kNoPolicy:
      time_limit_policy = ChildUserService::TimeLimitPolicyType::kNoTimeLimit;
      break;
    default:
      NOTREACHED_IN_MIGRATION();
  }
  return time_limit_policy;
}
}  // namespace

// static
const char ChildUserService::kFamilyLinkHelperAppPackageName[] =
    "com.google.android.apps.kids.familylinkhelper";
// static
const char ChildUserService::kFamilyLinkHelperAppPlayStoreURL[] =
    "https://play.google.com/store/apps/"
    "details?id=com.google.android.apps.kids.familylinkhelper";

ChildUserService::TestApi::TestApi(ChildUserService* service)
    : service_(service) {}

ChildUserService::TestApi::~TestApi() = default;

app_time::AppTimeController* ChildUserService::TestApi::app_time_controller() {
  return service_->app_time_controller_.get();
}

// static
const char* ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest() {
  return kTimeLimitPolicyTypesHistogramName;
}

ChildUserService::ChildUserService(content::BrowserContext* context)
    : profile_(Profile::FromBrowserContext(context)),
      app_time_controller_(std::make_unique<app_time::AppTimeController>(
          profile_,
          base::BindRepeating(&ChildUserService::ReportTimeLimitPolicy,
                              base::Unretained(this)))),
      website_approval_notifier_(profile_) {
  DCHECK(profile_);
  app_time_controller_->Init();

  pref_change_registrar_.Init(profile_->GetPrefs());
  pref_change_registrar_.Add(
      prefs::kUsageTimeLimit,
      base::BindRepeating(&ChildUserService::ReportTimeLimitPolicy,
                          base::Unretained(this)));
}

ChildUserService::~ChildUserService() = default;

void ChildUserService::PauseWebActivity(const std::string& app_service_id) {
  NOTIMPLEMENTED();
}

void ChildUserService::ResumeWebActivity(const std::string& app_service_id) {
  NOTIMPLEMENTED();
}

std::optional<base::TimeDelta> ChildUserService::GetTimeLimitForApp(
    const std::string& app_service_id,
    apps::AppType app_type) {
  if (!app_time_controller_)
    return std::nullopt;

  return app_time_controller_->GetTimeLimitForApp(app_service_id, app_type);
}

app_time::AppActivityReportInterface::ReportParams
ChildUserService::GenerateAppActivityReport(
    enterprise_management::ChildStatusReportRequest* report) {
  DCHECK(app_time_controller_);
  app_time_controller_->app_registry()->GenerateHiddenApps(report);
  return app_time_controller_->app_registry()->GenerateAppActivityReport(
      report);
}

void ChildUserService::AppActivityReportSubmitted(
    base::Time report_generation_timestamp) {
  DCHECK(app_time_controller_);
  app_time_controller_->app_registry()->OnSuccessfullyReported(
      report_generation_timestamp);
}

bool ChildUserService::AppTimeLimitAllowlistedApp(
    const app_time::AppId& app_id) const {
  if (!app_time_controller_)
    return false;
  return app_time_controller_->app_registry()->IsAllowlistedApp(app_id);
}

void ChildUserService ::ReportTimeLimitPolicy() const {
  const base::Value::Dict& time_limit_prefs =
      profile_->GetPrefs()->GetDict(prefs::kUsageTimeLimit);

  std::set<usage_time_limit::PolicyType> enabled_policies =
      usage_time_limit::GetEnabledTimeLimitPolicies(time_limit_prefs);

  for (const auto& policy_type : enabled_policies) {
    TimeLimitPolicyType time_limit_policy = GetTimeLimitPolicyType(policy_type);

    // `enabled_policies` does not contains
    // usage_time_limit::PolicyType::kNoPolicy, so `time_limit_policy` never
    // equals to TimeLimitPolicyType::kNoTimeLimit.
    if (time_limit_policy == TimeLimitPolicyType::kNoTimeLimit)
      continue;

    base::UmaHistogramEnumeration(
        /*name=*/kTimeLimitPolicyTypesHistogramName,
        /*sample=*/time_limit_policy);
  }

  bool has_policy_enabled = !enabled_policies.empty();
  DCHECK(app_time_controller_);
  if (app_time_controller_->HasAppTimeLimitRestriction()) {
    base::UmaHistogramEnumeration(
        /*name=*/kTimeLimitPolicyTypesHistogramName,
        /*sample=*/TimeLimitPolicyType::kAppTimeLimit);
    has_policy_enabled = true;
  }

  if (!has_policy_enabled) {
    base::UmaHistogramEnumeration(
        /*name=*/kTimeLimitPolicyTypesHistogramName,
        /*sample=*/TimeLimitPolicyType::kNoTimeLimit);
  }
}

void ChildUserService::Shutdown() {
  if (app_time_controller_) {
    app_time_controller_->app_registry()->SaveAppActivity();
    app_time_controller_->RecordMetricsOnShutdown();
    app_time_controller_.reset();
  }
  pref_change_registrar_.Remove(prefs::kUsageTimeLimit);
}

}  // namespace ash