From 1604eb8d1778e7f98aa36fb105ba9cd1e47abeb4 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Tue, 28 Sep 2021 08:39:43 -0700 Subject: [PATCH] P3A: Record how long rewards were enabled. Measure how long Brave Rewards were enabled to better understand user interaction with the feature. The duration is recorded in a limited number of bins, reporting whether rewards are still enabled, have never been enabled, or if they were previously on and are now turned off, the rough amount of time they were enabled. It is necessary to set the initial `kNever` measurement from `OnLedgerInitialized`, since `OnPrefChanged` isn't called for the overall enable prefs at startup. Closes brave/brave-browser#18394 --- .../brave_rewards/browser/rewards_p3a.cc | 56 +++++++++++++++++++ .../brave_rewards/browser/rewards_p3a.h | 13 +++++ .../brave_rewards/browser/rewards_service.cc | 1 + .../browser/rewards_service_impl.cc | 5 +- components/brave_rewards/common/pref_names.cc | 1 + components/brave_rewards/common/pref_names.h | 1 + components/p3a/brave_p3a_service.cc | 1 + 7 files changed, 77 insertions(+), 1 deletion(-) diff --git a/components/brave_rewards/browser/rewards_p3a.cc b/components/brave_rewards/browser/rewards_p3a.cc index 80b20bef02d0d..663865dd0f1c4 100644 --- a/components/brave_rewards/browser/rewards_p3a.cc +++ b/components/brave_rewards/browser/rewards_p3a.cc @@ -180,6 +180,62 @@ double CalcWalletBalance(base::flat_map wallets, return balance_minus_grant; } +void RecordRewardsEnabledDuration(PrefService* prefs, bool rewards_enabled) { + auto enabled_timestamp = prefs->GetTime(prefs::kEnabledTimestamp); + auto value = RewardsEnabledDuration::kNever; + + if (enabled_timestamp.is_null()) { + // No previous timestamp, so record one of the non-duration states. + if (!rewards_enabled) { + // Rewards have been disabled with no previous timestamp. + // Probably they've been on since we started measuring. + // Ignore this interval since we can't measure it and treat it + // the same as never having enabled. + value = RewardsEnabledDuration::kNever; + } else { + // Rewards have been enabled. + // Remember when so we can measure the duration on later changes. + prefs->SetTime(prefs::kEnabledTimestamp, base::Time::Now()); + value = RewardsEnabledDuration::kStillEnabled; + } + } else { + // Previous timestamp available. + if (!rewards_enabled) { + // Rewards have been disabled. Record the duration they were on. + // Set the threshold at three units so each bin represents the + // nominal value as an order-of-magnitude: more than three days + // is a week, more than three weeks is a month, and so on. + constexpr auto threshold = 3; + constexpr auto days_per_week = 7; + constexpr auto days_per_month = 30.44; // average length + auto duration = base::Time::Now() - enabled_timestamp; + if (duration < base::Hours(threshold)) { + value = RewardsEnabledDuration::kHours; + } else if (duration < base::Days(threshold)) { + value = RewardsEnabledDuration::kDays; + } else if (duration < base::Days(threshold * days_per_week)) { + value = RewardsEnabledDuration::kWeeks; + } else if (duration < base::Days(threshold * days_per_month)) { + value = RewardsEnabledDuration::kMonths; + } else { + value = RewardsEnabledDuration::kLonger; + } + // Null the timestamp so we're ready for a fresh measurement. + prefs->SetTime(prefs::kEnabledTimestamp, base::Time()); + } else { + // Rewards have been enabled. Overwrite the previous timestamp. + // Normally we null the timestamp when rewards are disabled, + // so typically we'll take the other `else` branch above instead. + // We nevertheless mark a new timestamp here to maintain consistent + // measurement even if our prefs change through some other path. + prefs->SetTime(prefs::kEnabledTimestamp, base::Time::Now()); + value = RewardsEnabledDuration::kStillEnabled; + } + } + + UMA_HISTOGRAM_ENUMERATION("Brave.Rewards.EnabledDuration", value); +} + void ExtractAndLogStats(const base::DictionaryValue& dict) { const base::Value* probi_value = dict.FindPath({"walletProperties", "probi_"}); diff --git a/components/brave_rewards/browser/rewards_p3a.h b/components/brave_rewards/browser/rewards_p3a.h index ee1ed36b769f2..bff46291f59a3 100644 --- a/components/brave_rewards/browser/rewards_p3a.h +++ b/components/brave_rewards/browser/rewards_p3a.h @@ -73,6 +73,19 @@ void RecordNoWalletCreatedForAllMetrics(); void RecordRewardsDisabledForSomeMetrics(); +enum class RewardsEnabledDuration { + kNever, + kStillEnabled, + kHours, + kDays, + kWeeks, + kMonths, + kLonger, + kMaxValue = kLonger, +}; + +void RecordRewardsEnabledDuration(PrefService* prefs, bool rewards_enabled); + double CalcWalletBalance(base::flat_map wallets, double user_funds); diff --git a/components/brave_rewards/browser/rewards_service.cc b/components/brave_rewards/browser/rewards_service.cc index a27d4e7ec4d6e..33cb0c5f823c6 100644 --- a/components/brave_rewards/browser/rewards_service.cc +++ b/components/brave_rewards/browser/rewards_service.cc @@ -43,6 +43,7 @@ void RewardsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { registry->RegisterBooleanPref(prefs::kUserHasClaimedGrant, false); registry->RegisterTimePref(prefs::kAddFundsNotification, base::Time()); registry->RegisterBooleanPref(prefs::kEnabled, false); + registry->RegisterTimePref(prefs::kEnabledTimestamp, base::Time()); registry->RegisterDictionaryPref(prefs::kExternalWallets); registry->RegisterUint64Pref(prefs::kServerPublisherListStamp, 0ull); registry->RegisterStringPref(prefs::kUpholdAnonAddress, ""); diff --git a/components/brave_rewards/browser/rewards_service_impl.cc b/components/brave_rewards/browser/rewards_service_impl.cc index 1b90b0bdd9b6a..bebc93e402096 100644 --- a/components/brave_rewards/browser/rewards_service_impl.cc +++ b/components/brave_rewards/browser/rewards_service_impl.cc @@ -433,12 +433,14 @@ void RewardsServiceImpl::OnPreferenceChanged(const std::string& key) { } if (key == prefs::kAutoContributeEnabled || key == ads::prefs::kEnabled) { - if (IsRewardsEnabled()) { + bool rewards_enabled = IsRewardsEnabled(); + if (rewards_enabled) { RecordBackendP3AStats(); } else { p3a::RecordRewardsDisabledForSomeMetrics(); p3a::RecordWalletState({.wallet_created = true}); } + p3a::RecordRewardsEnabledDuration(profile_->GetPrefs(), rewards_enabled); } } @@ -857,6 +859,7 @@ void RewardsServiceImpl::OnLedgerInitialized(ledger::type::Result result) { } else { p3a::RecordRewardsDisabledForSomeMetrics(); } + p3a::RecordRewardsEnabledDuration(profile_->GetPrefs(), IsRewardsEnabled()); GetBraveWallet( base::BindOnce(&RewardsServiceImpl::OnGetBraveWalletForP3A, AsWeakPtr())); diff --git a/components/brave_rewards/common/pref_names.cc b/components/brave_rewards/common/pref_names.cc index e4518309c754c..6eb4fd3f92c5c 100644 --- a/components/brave_rewards/common/pref_names.cc +++ b/components/brave_rewards/common/pref_names.cc @@ -10,6 +10,7 @@ namespace prefs { const char kHideButton[] = "brave.hide_brave_rewards_button"; const char kEnabled[] = "brave.rewards.enabled"; +const char kEnabledTimestamp[] = "brave.rewards.enabled_timestamp"; const char kNotifications[] = "brave.rewards.notifications"; const char kNotificationTimerInterval[]= "brave.rewards.notification_timer_interval"; diff --git a/components/brave_rewards/common/pref_names.h b/components/brave_rewards/common/pref_names.h index a3cd3e8e10448..7eb6988cf052b 100644 --- a/components/brave_rewards/common/pref_names.h +++ b/components/brave_rewards/common/pref_names.h @@ -11,6 +11,7 @@ namespace prefs { extern const char kHideButton[]; extern const char kEnabled[]; // DEPRECATED +extern const char kEnabledTimestamp[]; extern const char kNotifications[]; extern const char kNotificationTimerInterval[]; extern const char kBackupNotificationInterval[]; diff --git a/components/p3a/brave_p3a_service.cc b/components/p3a/brave_p3a_service.cc index af7df0e52a52c..9a645de0a4152 100644 --- a/components/p3a/brave_p3a_service.cc +++ b/components/p3a/brave_p3a_service.cc @@ -78,6 +78,7 @@ constexpr const char* kCollectedHistograms[] = { "Brave.Rewards.AdsState.2", "Brave.Rewards.AutoContributionsState.2", "Brave.Rewards.TipsState.2", + "Brave.Rewards.EnabledDuration", "Brave.Rewards.WalletBalance.2", "Brave.Rewards.WalletState", "Brave.Savings.BandwidthSavingsMB",