// 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 COMPONENTS_GUEST_OS_GUEST_OS_ENGAGEMENT_METRICS_H_
#define COMPONENTS_GUEST_OS_GUEST_OS_ENGAGEMENT_METRICS_H_
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "ui/wm/public/activation_change_observer.h"
class PrefService;
namespace aura {
class Window;
} // namespace aura
namespace base {
class Clock;
class TickClock;
} // namespace base
namespace guest_os {
// A class for recording engagement metrics. Calculates and reports daily
// totals for the following metrics:
// - Foo.EngagementTime.Total: Engaged session time, i.e. excluding when the
// screen is locked or dim due to user idle. To allow comparisons with the
// other metrics, this class should only be instantiated when the relevant
// Guest OS is supported.
// - Foo.EngagementTime.Foreground: Time when the user is engaged and focused
// on a matching window.
// - Foo.EngagementTime.Background: Time when the user is engaged and not
// focused on a matching window, but the Guest OS is otherwise active in the
// background.
// - Foo.Engagement.FooTotal: Total of Foreground and Background.
class GuestOsEngagementMetrics : public wm::ActivationChangeObserver,
public session_manager::SessionManagerObserver,
public chromeos::PowerManagerClient::Observer {
public:
using WindowMatcher = base::RepeatingCallback<bool(const aura::Window*)>;
GuestOsEngagementMetrics(PrefService* pref_service,
WindowMatcher window_matcher,
const std::string& pref_prefix,
const std::string& uma_name);
GuestOsEngagementMetrics(const GuestOsEngagementMetrics&) = delete;
GuestOsEngagementMetrics& operator=(const GuestOsEngagementMetrics&) = delete;
~GuestOsEngagementMetrics() override;
// Instead of using |window_matcher_|, we let consumers define when the Guest
// OS is active in the background. This function should be called whenever
// changes.
void SetBackgroundActive(bool background_active);
// wm::ActivationChangeObserver:
void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
// session_manager::SessionManagerObserver:
void OnSessionStateChanged() override;
// chromeos::PowerManagerClient::Observer:
void ScreenIdleStateChanged(
const power_manager::ScreenIdleState& proto) override;
static std::unique_ptr<GuestOsEngagementMetrics>
GetEngagementMetricsForTesting(PrefService* pref_service,
WindowMatcher window_matcher,
const std::string& pref_prefix,
const std::string& uma_name,
const base::Clock* clock,
const base::TickClock* tick_clock);
private:
// Private, for testing use only
GuestOsEngagementMetrics(PrefService* pref_service,
WindowMatcher window_matcher,
const std::string& pref_prefix,
const std::string& uma_name,
const base::Clock* clock,
const base::TickClock* tick_clock);
// Restores accumulated engagement time in previous sessions from profile
// preferences.
void RestoreEngagementTimeFromPrefs();
// Called periodically to save accumulated results to profile preferences.
void SaveEngagementTimeToPrefs();
// Called whenever engagement state is changed. Time spent in last state is
// accumulated to corresponding metrics.
void UpdateEngagementTime();
// Records accumulated engagement time metrics to UMA if necessary (i.e. day
// has changed).
void RecordEngagementTimeToUmaIfNeeded();
// Resets accumulated engagement times to zero, and updates both OS version
// and day ID.
void ResetEngagementTimePrefs();
bool ShouldAccumulateEngagementTotalTime() const;
bool ShouldAccumulateEngagementForegroundTime() const;
bool ShouldAccumulateEngagementBackgroundTime() const;
bool ShouldRecordEngagementTimeToUma() const;
const raw_ptr<PrefService> pref_service_;
WindowMatcher window_matcher_;
std::string pref_prefix_;
std::string uma_name_;
// |clock_| is used for determining when to log to UMA, while |tick_clock_|
// is used to calculate elapsed time.
raw_ptr<const base::Clock> clock_;
raw_ptr<const base::TickClock> tick_clock_;
base::RepeatingTimer update_engagement_time_timer_;
base::RepeatingTimer save_engagement_time_to_prefs_timer_;
base::TimeTicks last_update_ticks_;
// States for determining which engagement metrics should we accumulate to.
bool session_active_ = false;
bool screen_dimmed_ = false;
bool background_active_ = false;
bool matched_window_active_ = false;
// Accumulated results and associated state which are saved to profile
// preferences at fixed interval.
int day_id_ = 0;
base::TimeDelta engagement_time_total_;
base::TimeDelta engagement_time_foreground_;
base::TimeDelta engagement_time_background_;
};
} // namespace guest_os
#endif // COMPONENTS_GUEST_OS_GUEST_OS_ENGAGEMENT_METRICS_H_