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",