// 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.
#ifndef CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_TIME_CONTROLLER_H_
#define CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_TIME_CONTROLLER_H_
#include <memory>
#include <optional>
#include <string>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/child_accounts/time_limits/app_activity_registry.h"
#include "chrome/browser/ash/child_accounts/time_limits/app_time_notification_delegate.h"
#include "chromeos/ash/components/dbus/system_clock/system_clock_client.h"
#include "chromeos/ash/components/settings/timezone_settings.h"
#include "components/services/app_service/public/cpp/app_types.h"
class Profile;
class PrefRegistrySimple;
class PrefChangeRegistrar;
class PrefService;
class Profile;
namespace base {
class OneShotTimer;
} // namespace base
namespace gfx {
class ImageSkia;
} // namespace gfx
namespace ash {
namespace app_time {
extern const char kAppsWithTimeLimitMetric[];
extern const char kBlockedAppsCountMetric[];
extern const char kPolicyChangeCountMetric[];
extern const char kEngagementMetric[];
class AppServiceWrapper;
// Coordinates per-app time limit for child user.
class AppTimeController : public SystemClockClient::Observer,
public system::TimezoneSettings::Observer,
public AppTimeNotificationDelegate,
public AppActivityRegistry::AppStateObserver {
public:
// Used for tests to get internal implementation details.
class TestApi {
public:
explicit TestApi(AppTimeController* controller);
~TestApi();
void SetLastResetTime(base::Time time);
base::Time GetNextResetTime() const;
base::Time GetLastResetTime() const;
AppActivityRegistry* app_registry();
private:
const raw_ptr<AppTimeController, DanglingUntriaged> controller_;
};
// Registers preferences
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
AppTimeController(Profile* profile,
base::RepeatingClosure on_policy_updated_callback);
AppTimeController(const AppTimeController&) = delete;
AppTimeController& operator=(const AppTimeController&) = delete;
~AppTimeController() override;
// Initializes AppTimeController. It should be called after the constructor.
void Init();
bool IsExtensionAllowlisted(const std::string& extension_id) const;
// Returns current time limit for the app identified by |app_service_id| and
// |app_type|.Will return nullopt if there is no limit set or app is not
// tracked.
std::optional<base::TimeDelta> GetTimeLimitForApp(
const std::string& app_service_id,
apps::AppType app_type) const;
// Called by ChildUserService when it is being destructed to save metrics.
void RecordMetricsOnShutdown() const;
// SystemClockClient::Observer:
void SystemClockUpdated() override;
// system::TimezoneSetting::Observer:
void TimezoneChanged(const icu::TimeZone& timezone) override;
// AppTimeNotificationDelegate:
void ShowAppTimeLimitNotification(
const AppId& app_id,
const std::optional<base::TimeDelta>& time_limit,
AppNotification notification) override;
// AppActivityRegistry::AppStateObserver:
void OnAppLimitReached(const AppId& app_id,
base::TimeDelta time_limit,
bool was_active) override;
void OnAppLimitRemoved(const AppId& app_id) override;
void OnAppInstalled(const AppId& app_id) override;
const AppActivityRegistry* app_registry() const {
return app_registry_.get();
}
AppActivityRegistry* app_registry() { return app_registry_.get(); }
// Returns true if there is any app time limit set for current user.
bool HasAppTimeLimitRestriction() const;
private:
void RegisterProfilePrefObservers(PrefService* pref_service);
void TimeLimitsPolicyUpdated(const std::string& pref_name);
void TimeLimitsAllowlistPolicyUpdated(const std::string& pref_name);
base::Time GetNextResetTime() const;
void ScheduleForTimeLimitReset();
void OnResetTimeReached();
void RestoreLastResetTime();
void SetLastResetTime(base::Time timestamp);
// Called when the system time or timezone may have changed.
bool HasTimeCrossedResetBoundary() const;
void OpenFamilyLinkApp();
void ShowNotificationForApp(const std::string& app_name,
AppNotification notification,
std::optional<base::TimeDelta> time_limit,
std::optional<gfx::ImageSkia> icon);
// Profile
const raw_ptr<Profile> profile_;
// The time of the day when app time limits should be reset.
// Defaults to 6am local time.
base::TimeDelta limits_reset_time_ = base::Hours(6);
// The last time when |reset_timer_| fired.
base::Time last_limits_reset_time_;
// Timer scheduled for the next reset of app time limits.
// Only set when |reset_time_| is
base::OneShotTimer reset_timer_{base::DefaultTickClock::GetInstance()};
std::unique_ptr<AppServiceWrapper> app_service_wrapper_;
std::unique_ptr<AppActivityRegistry> app_registry_;
// Used to observe when policy preferences change.
std::unique_ptr<PrefChangeRegistrar> pref_registrar_;
// Metrics information to be recorded for PerAppTimeLimits.
int patl_policy_update_count_ = 0;
int apps_with_limit_ = 0;
base::RepeatingClosure on_policy_updated_callback_;
base::WeakPtrFactory<AppTimeController> weak_ptr_factory_{this};
};
} // namespace app_time
} // namespace ash
#endif // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_TIME_CONTROLLER_H_