Skip to content

Commit

Permalink
Add VPN widget metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
DJAndries committed Nov 27, 2024
1 parent 9f94076 commit 51fef07
Show file tree
Hide file tree
Showing 14 changed files with 325 additions and 126 deletions.
8 changes: 8 additions & 0 deletions browser/ui/webui/new_tab_page/brave_new_tab_page_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,14 @@ void BraveNewTabPageHandler::OpenVPNAccountPage() {
#endif
}

void BraveNewTabPageHandler::ReportVPNWidgetUsage() {
#if BUILDFLAG(ENABLE_BRAVE_VPN)
auto* vpn_service =
brave_vpn::BraveVpnServiceFactory::GetForProfile(profile_);
vpn_service->brave_vpn_metrics()->RecordWidgetUsage(true);
#endif
}

bool BraveNewTabPageHandler::IsCustomBackgroundImageEnabled() const {
if (profile_->GetPrefs()->IsManagedPreference(GetThemePrefNameInMigration(
ThemePrefInMigration::kNtpCustomBackgroundDict))) {
Expand Down
1 change: 1 addition & 0 deletions browser/ui/webui/new_tab_page/brave_new_tab_page_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class BraveNewTabPageHandler : public brave_new_tab_page::mojom::PageHandler,
void RefreshVPNState() override;
void LaunchVPNPanel() override;
void OpenVPNAccountPage() override;
void ReportVPNWidgetUsage() override;

// Observe BraveNTPCustomBackgroundService.
void OnBackgroundUpdated();
Expand Down
3 changes: 3 additions & 0 deletions components/brave_new_tab_ui/async/brave_vpn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ handler.on<PurchasedState>(Actions.initialize.getType(),

handler.on(Actions.launchVPNPanel.getType(), async (store) => {
getNTPBrowserAPI().pageHandler.launchVPNPanel()
getNTPBrowserAPI().pageHandler.reportVPNWidgetUsage()
})

handler.on(Actions.openVPNAccountPage.getType(), async (store) => {
getNTPBrowserAPI().pageHandler.openVPNAccountPage()
getNTPBrowserAPI().pageHandler.reportVPNWidgetUsage()
})

handler.on(Actions.toggleConnection.getType(), async (store) => {
Expand All @@ -56,6 +58,7 @@ handler.on(Actions.toggleConnection.getType(), async (store) => {
} else {
getVPNServiceHandler().connect()
}
getNTPBrowserAPI().pageHandler.reportVPNWidgetUsage()
})

handler.on<PurchasedState>(
Expand Down
1 change: 1 addition & 0 deletions components/brave_new_tab_ui/brave_new_tab_page.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ interface PageHandler {
RefreshVPNState();
LaunchVPNPanel();
OpenVPNAccountPage();
ReportVPNWidgetUsage();
};

// WebUI-side handler for requests from the browser.
Expand Down
10 changes: 9 additions & 1 deletion components/brave_vpn/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ assert(enable_brave_vpn)

static_library("browser") {
sources = [
"brave_vpn_metrics.cc",
"brave_vpn_metrics.h",
"brave_vpn_service.cc",
"brave_vpn_service.h",
"brave_vpn_service_delegate.h",
Expand All @@ -26,10 +28,12 @@ static_library("browser") {
"//base",
"//brave/components/brave_vpn/common",
"//brave/components/brave_vpn/common/mojom",
"//brave/components/constants",
"//brave/components/p3a_utils",
"//brave/components/resources:strings",
"//brave/components/skus/browser",
"//brave/components/skus/common:mojom",
"//brave/components/time_period_storage",
"//brave/components/version_info",
"//build:buildflag_header_h",
"//components/keyed_service/core",
Expand All @@ -45,7 +49,10 @@ static_library("browser") {
source_set("unit_tests") {
testonly = true

sources = [ "brave_vpn_service_unittest.cc" ]
sources = [
"brave_vpn_metrics_unittest.cc",
"brave_vpn_service_unittest.cc",
]

deps = [
":browser",
Expand All @@ -57,6 +64,7 @@ source_set("unit_tests") {
"//brave/components/brave_vpn/browser/connection/wireguard/credentials:unit_tests",
"//brave/components/brave_vpn/common",
"//brave/components/brave_vpn/common/mojom",
"//brave/components/constants",
"//brave/components/skus/browser",
"//brave/components/skus/common",
"//brave/components/skus/common:mojom",
Expand Down
115 changes: 115 additions & 0 deletions components/brave_vpn/browser/brave_vpn_metrics.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "brave/components/brave_vpn/browser/brave_vpn_metrics.h"

#include "base/metrics/histogram_macros.h"
#include "brave/components/brave_vpn/common/brave_vpn_constants.h"
#include "brave/components/brave_vpn/common/pref_names.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/p3a_utils/bucket.h"
#include "brave/components/p3a_utils/feature_usage.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"

namespace brave_vpn {

namespace {

constexpr int kWidgetUsageBuckets[] = {1, 10, 20};

} // namespace

BraveVpnMetrics::BraveVpnMetrics(PrefService* local_state,
PrefService* profile_prefs)
: local_state_(local_state),
profile_prefs_(profile_prefs),
widget_usage_storage_(local_state_,
prefs::kBraveVPNWidgetUsageWeeklyStorage) {
pref_change_registrar_.Init(profile_prefs);
pref_change_registrar_.Add(
kNewTabPageShowBraveVPN,
base::BindRepeating(&BraveVpnMetrics::HandleShowWidgetChange,
base::Unretained(this)));
RecordAllMetrics(false);
}

BraveVpnMetrics::~BraveVpnMetrics() = default;

void BraveVpnMetrics::RecordAllMetrics(bool new_usage) {
if (new_usage) {
p3a_utils::RecordFeatureUsage(local_state_, prefs::kBraveVPNFirstUseTime,
prefs::kBraveVPNLastUseTime);
}
p3a_utils::RecordFeatureNewUserReturning(
local_state_, prefs::kBraveVPNFirstUseTime, prefs::kBraveVPNLastUseTime,
prefs::kBraveVPNUsedSecondDay, kNewUserReturningHistogramName);
p3a_utils::RecordFeatureDaysInMonthUsed(
local_state_, new_usage, prefs::kBraveVPNLastUseTime,
prefs::kBraveVPNDaysInMonthUsed, kDaysInMonthUsedHistogramName);
p3a_utils::RecordFeatureLastUsageTimeMetric(
local_state_, prefs::kBraveVPNLastUseTime, kLastUsageTimeHistogramName);
RecordWidgetUsage(false);
report_timer_.Start(FROM_HERE,
base::Time::Now() + base::Hours(kP3AIntervalHours),
base::BindOnce(&BraveVpnMetrics::RecordAllMetrics,
base::Unretained(this), false));
}

#if BUILDFLAG(IS_ANDROID)
void BraveVpnMetrics::RecordAndroidBackgroundP3A(int64_t session_start_time_ms,
int64_t session_end_time_ms) {
if (session_start_time_ms < 0 || session_end_time_ms < 0) {
RecordAllMetrics(false);
return;
}
base::Time session_start_time =
base::Time::FromMillisecondsSinceUnixEpoch(
static_cast<double>(session_start_time_ms))
.LocalMidnight();
base::Time session_end_time = base::Time::FromMillisecondsSinceUnixEpoch(
static_cast<double>(session_end_time_ms))
.LocalMidnight();
for (base::Time day = session_start_time; day <= session_end_time;
day += base::Days(1)) {
bool is_last_day = day == session_end_time;
// Call functions for each day in the last session to ensure
// p3a_util functions produce the correct result
p3a_utils::RecordFeatureUsage(local_state_, prefs::kBraveVPNFirstUseTime,
prefs::kBraveVPNLastUseTime, day);
p3a_utils::RecordFeatureNewUserReturning(
local_state_, prefs::kBraveVPNFirstUseTime, prefs::kBraveVPNLastUseTime,
prefs::kBraveVPNUsedSecondDay, kNewUserReturningHistogramName,
is_last_day);
p3a_utils::RecordFeatureDaysInMonthUsed(
local_state_, day, prefs::kBraveVPNLastUseTime,
prefs::kBraveVPNDaysInMonthUsed, kDaysInMonthUsedHistogramName,
is_last_day);
}
p3a_utils::RecordFeatureLastUsageTimeMetric(
local_state_, prefs::kBraveVPNLastUseTime, kLastUsageTimeHistogramName);
}
#endif

void BraveVpnMetrics::RecordWidgetUsage(bool new_usage) {
if (new_usage) {
widget_usage_storage_.AddDelta(1u);
}
auto total = widget_usage_storage_.GetWeeklySum();
if (total == 0) {
return;
}
p3a_utils::RecordToHistogramBucket(kWidgetUsageHistogramName,
kWidgetUsageBuckets, total);
}

void BraveVpnMetrics::HandleShowWidgetChange() {
if (profile_prefs_->GetBoolean(kNewTabPageShowBraveVPN)) {
return;
}
UMA_HISTOGRAM_BOOLEAN(kHideWidgetHistogramName, true);
}

} // namespace brave_vpn
57 changes: 57 additions & 0 deletions components/brave_vpn/browser/brave_vpn_metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_COMPONENTS_BRAVE_VPN_BROWSER_BRAVE_VPN_METRICS_H_
#define BRAVE_COMPONENTS_BRAVE_VPN_BROWSER_BRAVE_VPN_METRICS_H_

#include "base/timer/wall_clock_timer.h"
#include "brave/components/time_period_storage/weekly_storage.h"
#include "components/prefs/pref_change_registrar.h"

class PrefService;

namespace brave_vpn {

inline constexpr char kNewUserReturningHistogramName[] =
"Brave.VPN.NewUserReturning";
inline constexpr char kDaysInMonthUsedHistogramName[] =
"Brave.VPN.DaysInMonthUsed";
inline constexpr char kLastUsageTimeHistogramName[] = "Brave.VPN.LastUsageTime";
inline constexpr char kWidgetUsageHistogramName[] = "Brave.VPN.WidgetUsage";
inline constexpr char kHideWidgetHistogramName[] = "Brave.VPN.HideWidget";

class BraveVpnMetrics {
public:
BraveVpnMetrics(PrefService* local_prefs, PrefService* profile_prefs);
~BraveVpnMetrics();

BraveVpnMetrics(const BraveVpnMetrics&) = delete;
BraveVpnMetrics& operator=(const BraveVpnMetrics&) = delete;

// new_usage should be set to true if a new VPN connection was just
// established.
void RecordAllMetrics(bool new_usage);

#if BUILDFLAG(IS_ANDROID)
void RecordAndroidBackgroundP3A(int64_t session_start_time_ms,
int64_t session_end_time_ms);
#endif

void RecordWidgetUsage(bool new_usage);

private:
void HandleShowWidgetChange();

raw_ptr<PrefService> local_state_;
raw_ptr<PrefService> profile_prefs_;
PrefChangeRegistrar pref_change_registrar_;

WeeklyStorage widget_usage_storage_;
base::WallClockTimer report_timer_;
};

} // namespace brave_vpn

#endif // BRAVE_COMPONENTS_BRAVE_VPN_BROWSER_BRAVE_VPN_METRICS_H_
115 changes: 115 additions & 0 deletions components/brave_vpn/browser/brave_vpn_metrics_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "brave/components/brave_vpn/browser/brave_vpn_metrics.h"

#include <memory>

#include "base/test/metrics/histogram_tester.h"
#include "brave/components/brave_vpn/common/brave_vpn_utils.h"
#include "brave/components/constants/pref_names.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace brave_vpn {

class BraveVpnMetricsTest : public testing::Test {
public:
BraveVpnMetricsTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}

void SetUp() override {
base::Time future_mock_time;
if (base::Time::FromString("2023-01-04", &future_mock_time)) {
task_environment_.AdvanceClock(future_mock_time - base::Time::Now());
}
profile_prefs_.registry()->RegisterBooleanPref(kNewTabPageShowBraveVPN,
true);
brave_vpn::RegisterLocalStatePrefs(local_state_.registry());
metrics_ =
std::make_unique<BraveVpnMetrics>(&local_state_, &profile_prefs_);
}

protected:
content::BrowserTaskEnvironment task_environment_;
TestingPrefServiceSimple local_state_;
sync_preferences::TestingPrefServiceSyncable profile_prefs_;
std::unique_ptr<BraveVpnMetrics> metrics_;
base::HistogramTester histogram_tester_;
};

TEST_F(BraveVpnMetricsTest, NewUserReturningMetric) {
metrics_->RecordAllMetrics(false);
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 0, 2);

task_environment_.FastForwardBy(base::Days(1));
metrics_->RecordAllMetrics(true);
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 2, 1);

task_environment_.FastForwardBy(base::Days(1));
metrics_->RecordAllMetrics(true);
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 3, 1);

task_environment_.FastForwardBy(base::Days(6));
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 1, 1);
}

TEST_F(BraveVpnMetricsTest, DaysInMonthUsedMetric) {
metrics_->RecordAllMetrics(false);
histogram_tester_.ExpectTotalCount(kDaysInMonthUsedHistogramName, 0);

metrics_->RecordAllMetrics(true);
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 1, 1);

task_environment_.FastForwardBy(base::Days(1));
metrics_->RecordAllMetrics(true);
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 2, 1);
task_environment_.FastForwardBy(base::Days(1));
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 2, 2);

metrics_->RecordAllMetrics(true);
task_environment_.FastForwardBy(base::Days(30));
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 0, 1);
}

TEST_F(BraveVpnMetricsTest, LastUsageTimeMetric) {
histogram_tester_.ExpectTotalCount(kLastUsageTimeHistogramName, 0);

metrics_->RecordAllMetrics(true);
histogram_tester_.ExpectBucketCount(kLastUsageTimeHistogramName, 1, 1);

task_environment_.AdvanceClock(base::Days(10));
metrics_->RecordAllMetrics(true);
histogram_tester_.ExpectBucketCount(kLastUsageTimeHistogramName, 1, 2);
task_environment_.AdvanceClock(base::Days(10));
metrics_->RecordAllMetrics(false);
histogram_tester_.ExpectBucketCount(kLastUsageTimeHistogramName, 2, 1);
}

TEST_F(BraveVpnMetricsTest, WidgetUsageAndHideMetrics) {
histogram_tester_.ExpectTotalCount(kWidgetUsageHistogramName, 0);
histogram_tester_.ExpectTotalCount(kHideWidgetHistogramName, 0);

// Test widget usage recording
metrics_->RecordWidgetUsage(true);
histogram_tester_.ExpectUniqueSample(kWidgetUsageHistogramName, 0, 1);

// Record multiple usages
metrics_->RecordWidgetUsage(true);
metrics_->RecordWidgetUsage(true);
histogram_tester_.ExpectBucketCount(kWidgetUsageHistogramName, 1, 2);

profile_prefs_.SetBoolean(kNewTabPageShowBraveVPN, true);
histogram_tester_.ExpectTotalCount(kHideWidgetHistogramName, 0);
// Test hide widget metric
profile_prefs_.SetBoolean(kNewTabPageShowBraveVPN, false);
histogram_tester_.ExpectUniqueSample(kHideWidgetHistogramName, true, 1);

histogram_tester_.ExpectTotalCount(kWidgetUsageHistogramName, 3);
}

} // namespace brave_vpn
Loading

0 comments on commit 51fef07

Please sign in to comment.