Added VPN usage P3A
This commit is contained in:
@@ -255,6 +255,8 @@ public abstract class BraveActivity<C extends ChromeActivityComponent> extends C
|
||||
if (BraveVpnUtils.isBraveVpnFeatureEnable()) {
|
||||
InAppPurchaseWrapper.getInstance().startBillingServiceConnection(BraveActivity.this);
|
||||
BraveVpnNativeWorker.getInstance().addObserver(this);
|
||||
|
||||
BraveVpnUtils.reportBackgroundUsageP3A();
|
||||
}
|
||||
Tab tab = getActivityTab();
|
||||
if (tab != null) {
|
||||
|
||||
@@ -172,6 +172,15 @@ public class BraveVpnNativeWorker {
|
||||
mNativeBraveVpnNativeWorker, purchaseToken, productId, productType, packageName);
|
||||
}
|
||||
|
||||
public void reportBackgroundP3A(long sessionStartTimeMs, long sessionEndTimeMs) {
|
||||
BraveVpnNativeWorkerJni.get().reportBackgroundP3A(
|
||||
mNativeBraveVpnNativeWorker, sessionStartTimeMs, sessionEndTimeMs);
|
||||
}
|
||||
|
||||
public void reportForegroundP3A() {
|
||||
BraveVpnNativeWorkerJni.get().reportForegroundP3A(mNativeBraveVpnNativeWorker);
|
||||
}
|
||||
|
||||
@NativeMethods
|
||||
interface Natives {
|
||||
void init(BraveVpnNativeWorker caller);
|
||||
@@ -190,5 +199,8 @@ public class BraveVpnNativeWorker {
|
||||
String packageName);
|
||||
void verifyPurchaseToken(long nativeBraveVpnNativeWorker, String purchaseToken,
|
||||
String productId, String productType, String packageName);
|
||||
void reportBackgroundP3A(
|
||||
long nativeBraveVpnNativeWorker, long sessionStartTimeMs, long sessionEndTimeMs);
|
||||
void reportForegroundP3A(long nativeBraveVpnNativeWorker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ public class BraveVpnPrefUtils {
|
||||
public static final String PREF_BRAVE_VPN_SERVER_PUBLIC_KEY = "brave_vpn_server_public_key";
|
||||
public static final String PREF_BRAVE_VPN_IP_ADDRESS = "brave_vpn_ip_address";
|
||||
public static final String PREF_BRAVE_VPN_CLIENT_PRIVATE_KEY = "brave_vpn_client_private_key";
|
||||
public static final String PREF_SESSION_START_TIME = "brave_vpn_session_start_time";
|
||||
public static final String PREF_SESSION_END_TIME = "brave_vpn_session_end_time";
|
||||
|
||||
private static final SharedPreferences mSharedPreferences =
|
||||
ContextUtils.getAppSharedPreferences();
|
||||
@@ -268,4 +270,24 @@ public class BraveVpnPrefUtils {
|
||||
sharedPreferencesEditor.putStringSet(PREF_EXCLUDED_PACKAGES, packages);
|
||||
sharedPreferencesEditor.apply();
|
||||
}
|
||||
|
||||
public static void setSessionEndTimeMs(long timeMs) {
|
||||
SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
|
||||
sharedPreferencesEditor.putLong(PREF_SESSION_END_TIME, timeMs);
|
||||
sharedPreferencesEditor.apply();
|
||||
}
|
||||
|
||||
public static long getSessionEndTimeMs() {
|
||||
return mSharedPreferences.getLong(PREF_SESSION_END_TIME, -1);
|
||||
}
|
||||
|
||||
public static void setSessionStartTimeMs(long timeMs) {
|
||||
SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
|
||||
sharedPreferencesEditor.putLong(PREF_SESSION_START_TIME, timeMs);
|
||||
sharedPreferencesEditor.apply();
|
||||
}
|
||||
|
||||
public static long getSessionStartTimeMs() {
|
||||
return mSharedPreferences.getLong(PREF_SESSION_START_TIME, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.os.Build;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.chromium.chrome.R;
|
||||
import org.chromium.chrome.browser.vpn.BraveVpnNativeWorker;
|
||||
import org.chromium.chrome.browser.vpn.wireguard.WireguardService;
|
||||
import org.chromium.chrome.browser.vpn.wireguard.WireguardUtils;
|
||||
import org.chromium.ui.widget.Toast;
|
||||
@@ -62,6 +63,7 @@ public class BraveVpnProfileUtils {
|
||||
}
|
||||
|
||||
public void startVpn(Context context) {
|
||||
BraveVpnNativeWorker.getInstance().reportForegroundP3A();
|
||||
ContextCompat.startForegroundService(context, new Intent(context, WireguardService.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.chromium.base.ContextUtils;
|
||||
import org.chromium.base.Log;
|
||||
import org.chromium.chrome.R;
|
||||
import org.chromium.chrome.browser.util.BraveConstants;
|
||||
import org.chromium.chrome.browser.vpn.BraveVpnNativeWorker;
|
||||
import org.chromium.chrome.browser.vpn.activities.BraveVpnPlansActivity;
|
||||
import org.chromium.chrome.browser.vpn.activities.BraveVpnProfileActivity;
|
||||
import org.chromium.chrome.browser.vpn.activities.BraveVpnSupportActivity;
|
||||
@@ -241,4 +242,13 @@ public class BraveVpnUtils {
|
||||
((FragmentActivity) activity).getSupportFragmentManager(),
|
||||
"BraveVpnConfirmDialogFragment");
|
||||
}
|
||||
|
||||
public static void reportBackgroundUsageP3A() {
|
||||
// Will report previous/current session timestamps...
|
||||
BraveVpnNativeWorker.getInstance().reportBackgroundP3A(
|
||||
BraveVpnPrefUtils.getSessionStartTimeMs(), BraveVpnPrefUtils.getSessionEndTimeMs());
|
||||
// ...and then reset the timestamps so we don't report the same session again.
|
||||
BraveVpnPrefUtils.setSessionStartTimeMs(-1);
|
||||
BraveVpnPrefUtils.setSessionEndTimeMs(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.chromium.chrome.browser.vpn.DisconnectVpnBroadcastReceiver;
|
||||
import org.chromium.chrome.browser.vpn.utils.BraveVpnPrefUtils;
|
||||
import org.chromium.chrome.browser.vpn.utils.BraveVpnUtils;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@@ -43,6 +44,7 @@ public class WireguardServiceImpl
|
||||
private TunnelModel mTunnelModel;
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
private Timer mVpnStatisticsTimer;
|
||||
private Timer mRecordDaysUsedTimer;
|
||||
private static final int BRAVE_VPN_NOTIFICATION_ID = 801;
|
||||
private Context mContext = ContextUtils.getApplicationContext();
|
||||
|
||||
@@ -89,6 +91,8 @@ public class WireguardServiceImpl
|
||||
mTunnelModel = TunnelModel.createTunnel(config, this);
|
||||
mBackend.setState(mTunnelModel, Tunnel.State.UP, config);
|
||||
updateVpnStatisticsTimer();
|
||||
recordSessionTimes();
|
||||
updateRecordSessionTimesTimer();
|
||||
}
|
||||
|
||||
private Notification getBraveVpnNotification(String notificationText) {
|
||||
@@ -124,6 +128,39 @@ public class WireguardServiceImpl
|
||||
mNotificationManager.notify(BRAVE_VPN_NOTIFICATION_ID, notification);
|
||||
}
|
||||
|
||||
private void recordSessionTimes() {
|
||||
long sessionStartTimeMs = BraveVpnPrefUtils.getSessionStartTimeMs();
|
||||
long sessionEndTimeMs = BraveVpnPrefUtils.getSessionEndTimeMs();
|
||||
|
||||
Calendar sessionEndTimeCal = Calendar.getInstance();
|
||||
sessionEndTimeCal.setTimeInMillis(sessionEndTimeMs);
|
||||
Calendar currDate = Calendar.getInstance();
|
||||
|
||||
long currTimeMs = System.currentTimeMillis();
|
||||
if (sessionStartTimeMs < 0) {
|
||||
BraveVpnPrefUtils.setSessionStartTimeMs(currTimeMs);
|
||||
}
|
||||
|
||||
if (currDate.get(Calendar.YEAR) != sessionEndTimeCal.get(Calendar.YEAR)
|
||||
|| currDate.get(Calendar.MONTH) != sessionEndTimeCal.get(Calendar.MONTH)
|
||||
|| currDate.get(Calendar.DAY_OF_MONTH)
|
||||
!= sessionEndTimeCal.get(Calendar.DAY_OF_MONTH)) {
|
||||
BraveVpnPrefUtils.setSessionEndTimeMs(currTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRecordSessionTimesTimer() {
|
||||
// This timer will be active for the duration of the connection.
|
||||
// It will become inactive when the connection is terminated/service destroyed.
|
||||
mVpnStatisticsTimer = new Timer();
|
||||
mVpnStatisticsTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
recordSessionTimes();
|
||||
}
|
||||
}, 0, 60000);
|
||||
}
|
||||
|
||||
private void updateVpnStatisticsTimer() {
|
||||
mVpnStatisticsTimer = new Timer();
|
||||
mVpnStatisticsTimer.schedule(new TimerTask() {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "brave/components/brave_search_conversion/p3a.h"
|
||||
#include "brave/components/brave_shields/browser/ad_block_service.h"
|
||||
#include "brave/components/brave_shields/browser/brave_shields_p3a.h"
|
||||
#include "brave/components/brave_vpn/buildflags/buildflags.h"
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
#include "brave/components/decentralized_dns/utils.h"
|
||||
#include "brave/components/ntp_background_images/browser/ntp_background_images_service.h"
|
||||
@@ -42,6 +43,10 @@
|
||||
#include "chrome/browser/first_run/first_run.h"
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
#include "brave/components/brave_vpn/pref_names.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_WIDEVINE)
|
||||
#include "brave/browser/widevine/widevine_utils.h"
|
||||
#endif
|
||||
@@ -110,6 +115,10 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
|
||||
RegisterLocalStatePrefsForMigration(registry);
|
||||
|
||||
brave_search_conversion::p3a::RegisterLocalStatePrefs(registry);
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
brave_vpn::prefs::RegisterLocalStatePrefs(registry);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace brave
|
||||
|
||||
@@ -245,6 +245,24 @@ void BraveVpnNativeWorker::OnVerifyPurchaseToken(
|
||||
base::android::ConvertUTF8ToJavaString(env, json_response), success);
|
||||
}
|
||||
|
||||
void BraveVpnNativeWorker::ReportForegroundP3A(JNIEnv* env) {
|
||||
BraveVpnService* brave_vpn_service = GetBraveVpnService();
|
||||
if (brave_vpn_service) {
|
||||
// Reporting a new session to P3A functions.
|
||||
brave_vpn_service->RecordP3A(true);
|
||||
}
|
||||
}
|
||||
|
||||
void BraveVpnNativeWorker::ReportBackgroundP3A(JNIEnv* env,
|
||||
jlong session_start_time_ms,
|
||||
jlong session_end_time_ms) {
|
||||
BraveVpnService* brave_vpn_service = GetBraveVpnService();
|
||||
if (brave_vpn_service) {
|
||||
brave_vpn_service->RecordAndroidBackgroundP3A(session_start_time_ms,
|
||||
session_end_time_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static void JNI_BraveVpnNativeWorker_Init(
|
||||
JNIEnv* env,
|
||||
const base::android::JavaParamRef<jobject>& jcaller) {
|
||||
|
||||
@@ -90,6 +90,11 @@ class BraveVpnNativeWorker {
|
||||
|
||||
void OnVerifyPurchaseToken(const std::string& json_response, bool success);
|
||||
|
||||
void ReportForegroundP3A(JNIEnv* env);
|
||||
void ReportBackgroundP3A(JNIEnv* env,
|
||||
jlong session_start_time_ms,
|
||||
jlong session_end_time_ms);
|
||||
|
||||
private:
|
||||
JavaObjectWeakGlobalRef weak_java_brave_vpn_native_worker_;
|
||||
base::WeakPtrFactory<BraveVpnNativeWorker> weak_factory_;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "brave/components/brave_vpn/brave_vpn_utils.h"
|
||||
#include "brave/components/skus/common/features.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/profiles/incognito_helpers.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "components/keyed_service/content/browser_context_dependency_manager.h"
|
||||
@@ -69,14 +70,16 @@ KeyedService* BraveVpnServiceFactory::BuildServiceInstanceFor(
|
||||
auto* default_storage_partition = context->GetDefaultStoragePartition();
|
||||
auto shared_url_loader_factory =
|
||||
default_storage_partition->GetURLLoaderFactoryForBrowserProcess();
|
||||
auto* local_state = g_browser_process->local_state();
|
||||
|
||||
auto callback = base::BindRepeating(
|
||||
[](content::BrowserContext* context) {
|
||||
return skus::SkusServiceFactory::GetForContext(context);
|
||||
},
|
||||
context);
|
||||
auto* vpn_service = new BraveVpnService(
|
||||
shared_url_loader_factory, user_prefs::UserPrefs::Get(context), callback);
|
||||
auto* vpn_service =
|
||||
new BraveVpnService(shared_url_loader_factory, local_state,
|
||||
user_prefs::UserPrefs::Get(context), callback);
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
auto* dns_observer_service =
|
||||
brave_vpn::BraveVpnDnsObserverFactory::GetInstance()
|
||||
|
||||
@@ -26,6 +26,7 @@ static_library("brave_vpn") {
|
||||
"mojom",
|
||||
"//base",
|
||||
"//brave/components/api_request_helper:api_request_helper",
|
||||
"//brave/components/p3a_utils",
|
||||
"//brave/components/resources:strings",
|
||||
"//brave/components/skus/browser",
|
||||
"//brave/components/skus/common",
|
||||
@@ -113,6 +114,7 @@ source_set("unit_tests") {
|
||||
deps = [
|
||||
":brave_vpn",
|
||||
"//base",
|
||||
"//brave/components/p3a_utils",
|
||||
"//brave/components/skus/browser",
|
||||
"//brave/components/skus/common",
|
||||
"//brave/components/skus/common:mojom",
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#include "base/json/json_reader.h"
|
||||
#include "base/json/json_writer.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "brave/components/brave_vpn/brave_vpn_utils.h"
|
||||
#include "brave/components/brave_vpn/pref_names.h"
|
||||
#include "brave/components/p3a_utils/feature_usage.h"
|
||||
#include "brave/components/skus/browser/skus_utils.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "net/base/network_change_notifier.h"
|
||||
@@ -53,6 +55,8 @@ constexpr char kVerifyPurchaseToken[] = "api/v1.1/verify-purchase-token";
|
||||
constexpr char kCreateSubscriberCredentialV12[] =
|
||||
"api/v1.2/subscriber-credential/create";
|
||||
|
||||
constexpr int kP3AIntervalHours = 24;
|
||||
|
||||
net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag() {
|
||||
return net::DefineNetworkTrafficAnnotation("brave_vpn_service", R"(
|
||||
semantics {
|
||||
@@ -114,10 +118,12 @@ using PurchasedState = mojom::PurchasedState;
|
||||
|
||||
BraveVpnService::BraveVpnService(
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
|
||||
PrefService* prefs,
|
||||
PrefService* local_prefs,
|
||||
PrefService* profile_prefs,
|
||||
base::RepeatingCallback<mojo::PendingRemote<skus::mojom::SkusService>()>
|
||||
skus_service_getter)
|
||||
: prefs_(prefs),
|
||||
: local_prefs_(local_prefs),
|
||||
profile_prefs_(profile_prefs),
|
||||
skus_service_getter_(skus_service_getter),
|
||||
api_request_helper_(GetNetworkTrafficAnnotationTag(),
|
||||
url_loader_factory) {
|
||||
@@ -137,18 +143,21 @@ BraveVpnService::BraveVpnService(
|
||||
// To prevent this, we load purchased state at startup only
|
||||
// when profile has cached region list because region list is fetched
|
||||
// and cached only when user purchased at least once.
|
||||
auto* preference = prefs_->FindPreference(prefs::kBraveVPNRegionList);
|
||||
auto* preference = profile_prefs_->FindPreference(prefs::kBraveVPNRegionList);
|
||||
if (preference && !preference->IsDefaultValue()) {
|
||||
ReloadPurchasedState();
|
||||
}
|
||||
base::PowerMonitor::AddPowerSuspendObserver(this);
|
||||
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
InitP3A();
|
||||
}
|
||||
|
||||
BraveVpnService::~BraveVpnService() {}
|
||||
|
||||
std::string BraveVpnService::GetCurrentEnvironment() const {
|
||||
return prefs_->GetString(prefs::kBraveVPNEEnvironment);
|
||||
return profile_prefs_->GetString(prefs::kBraveVPNEEnvironment);
|
||||
}
|
||||
|
||||
void BraveVpnService::ReloadPurchasedState() {
|
||||
@@ -265,6 +274,8 @@ void BraveVpnService::OnConnected() {
|
||||
}
|
||||
|
||||
UpdateAndNotifyConnectionStateChange(ConnectionState::CONNECTED);
|
||||
|
||||
RecordP3A(true);
|
||||
}
|
||||
|
||||
void BraveVpnService::OnIsConnecting() {
|
||||
@@ -445,7 +456,7 @@ void BraveVpnService::LoadCachedRegionData() {
|
||||
if (GetDeviceRegion().empty())
|
||||
return;
|
||||
|
||||
auto* preference = prefs_->FindPreference(prefs::kBraveVPNRegionList);
|
||||
auto* preference = profile_prefs_->FindPreference(prefs::kBraveVPNRegionList);
|
||||
DCHECK(preference);
|
||||
// Early return when we don't have any cached region data.
|
||||
if (preference->IsDefaultValue())
|
||||
@@ -472,7 +483,8 @@ void BraveVpnService::SetRegionListToPrefs() {
|
||||
for (const auto& region : regions_) {
|
||||
regions_list.Append(GetValueFromRegion(region));
|
||||
}
|
||||
prefs_->Set(prefs::kBraveVPNRegionList, base::Value(std::move(regions_list)));
|
||||
profile_prefs_->Set(prefs::kBraveVPNRegionList,
|
||||
base::Value(std::move(regions_list)));
|
||||
}
|
||||
|
||||
void BraveVpnService::OnFetchRegionList(bool background_fetch,
|
||||
@@ -582,22 +594,22 @@ void BraveVpnService::SetDeviceRegionWithTimezone(
|
||||
|
||||
void BraveVpnService::SetDeviceRegion(const std::string& name) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
prefs_->SetString(prefs::kBraveVPNDeviceRegion, name);
|
||||
profile_prefs_->SetString(prefs::kBraveVPNDeviceRegion, name);
|
||||
}
|
||||
|
||||
void BraveVpnService::SetSelectedRegion(const std::string& name) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
prefs_->SetString(prefs::kBraveVPNSelectedRegion, name);
|
||||
profile_prefs_->SetString(prefs::kBraveVPNSelectedRegion, name);
|
||||
}
|
||||
|
||||
std::string BraveVpnService::GetDeviceRegion() const {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
return prefs_->GetString(prefs::kBraveVPNDeviceRegion);
|
||||
return profile_prefs_->GetString(prefs::kBraveVPNDeviceRegion);
|
||||
}
|
||||
|
||||
std::string BraveVpnService::GetSelectedRegion() const {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
return prefs_->GetString(prefs::kBraveVPNSelectedRegion);
|
||||
return profile_prefs_->GetString(prefs::kBraveVPNSelectedRegion);
|
||||
}
|
||||
|
||||
void BraveVpnService::SetFallbackDeviceRegion() {
|
||||
@@ -882,17 +894,18 @@ void BraveVpnService::GetPurchaseToken(GetPurchaseTokenCallback callback) {
|
||||
// Get the Android purchase token (for Google Play Store).
|
||||
// The value for this is validated on the account.brave.com side
|
||||
auto* purchase_token =
|
||||
prefs_->FindPreference(prefs::kBraveVPNPurchaseTokenAndroid);
|
||||
profile_prefs_->FindPreference(prefs::kBraveVPNPurchaseTokenAndroid);
|
||||
if (purchase_token && !purchase_token->IsDefaultValue()) {
|
||||
purchase_token_string =
|
||||
prefs_->GetString(prefs::kBraveVPNPurchaseTokenAndroid);
|
||||
profile_prefs_->GetString(prefs::kBraveVPNPurchaseTokenAndroid);
|
||||
}
|
||||
|
||||
// Package name is important; for real users, it'll be the Release package.
|
||||
// For testing we do have the ability to use the Nightly package.
|
||||
auto* package = prefs_->FindPreference(prefs::kBraveVPNPackageAndroid);
|
||||
auto* package =
|
||||
profile_prefs_->FindPreference(prefs::kBraveVPNPackageAndroid);
|
||||
if (package && !package->IsDefaultValue()) {
|
||||
package_string = prefs_->GetString(prefs::kBraveVPNPackageAndroid);
|
||||
package_string = profile_prefs_->GetString(prefs::kBraveVPNPackageAndroid);
|
||||
}
|
||||
|
||||
base::Value response(base::Value::Type::DICTIONARY);
|
||||
@@ -1065,6 +1078,65 @@ void BraveVpnService::OnPrepareCredentialsPresentation(
|
||||
#endif
|
||||
}
|
||||
|
||||
void BraveVpnService::InitP3A() {
|
||||
p3a_timer_.Start(FROM_HERE, base::Hours(kP3AIntervalHours), this,
|
||||
&BraveVpnService::OnP3AInterval);
|
||||
RecordP3A(false);
|
||||
}
|
||||
|
||||
void BraveVpnService::RecordP3A(bool new_usage) {
|
||||
if (new_usage) {
|
||||
p3a_utils::RecordFeatureUsage(local_prefs_, prefs::kBraveVPNFirstUseTime,
|
||||
prefs::kBraveVPNLastUseTime);
|
||||
}
|
||||
p3a_utils::RecordFeatureNewUserReturning(
|
||||
local_prefs_, prefs::kBraveVPNFirstUseTime, prefs::kBraveVPNLastUseTime,
|
||||
prefs::kBraveVPNUsedSecondDay, kNewUserReturningHistogramName);
|
||||
p3a_utils::RecordFeatureDaysInMonthUsed(
|
||||
local_prefs_, new_usage, prefs::kBraveVPNLastUseTime,
|
||||
prefs::kBraveVPNDaysInMonthUsed, kDaysInMonthUsedHistogramName);
|
||||
p3a_utils::RecordFeatureLastUsageTimeMetric(
|
||||
local_prefs_, prefs::kBraveVPNLastUseTime, kLastUsageTimeHistogramName);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
void BraveVpnService::RecordAndroidBackgroundP3A(int64_t session_start_time_ms,
|
||||
int64_t session_end_time_ms) {
|
||||
if (session_start_time_ms < 0 || session_end_time_ms < 0) {
|
||||
RecordP3A(false);
|
||||
return;
|
||||
}
|
||||
base::Time session_start_time =
|
||||
base::Time::FromJsTime(static_cast<double>(session_start_time_ms))
|
||||
.LocalMidnight();
|
||||
base::Time session_end_time =
|
||||
base::Time::FromJsTime(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_prefs_, prefs::kBraveVPNFirstUseTime,
|
||||
prefs::kBraveVPNLastUseTime, day);
|
||||
p3a_utils::RecordFeatureNewUserReturning(
|
||||
local_prefs_, prefs::kBraveVPNFirstUseTime, prefs::kBraveVPNLastUseTime,
|
||||
prefs::kBraveVPNUsedSecondDay, kNewUserReturningHistogramName,
|
||||
is_last_day);
|
||||
p3a_utils::RecordFeatureDaysInMonthUsed(
|
||||
local_prefs_, day, prefs::kBraveVPNLastUseTime,
|
||||
prefs::kBraveVPNDaysInMonthUsed, kDaysInMonthUsedHistogramName,
|
||||
is_last_day);
|
||||
}
|
||||
p3a_utils::RecordFeatureLastUsageTimeMetric(
|
||||
local_prefs_, prefs::kBraveVPNLastUseTime, kLastUsageTimeHistogramName);
|
||||
}
|
||||
#endif
|
||||
|
||||
void BraveVpnService::OnP3AInterval() {
|
||||
RecordP3A(false);
|
||||
}
|
||||
|
||||
void BraveVpnService::SetPurchasedState(const std::string& env,
|
||||
PurchasedState state) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
@@ -1079,7 +1151,7 @@ void BraveVpnService::SetPurchasedState(const std::string& env,
|
||||
}
|
||||
|
||||
void BraveVpnService::SetCurrentEnvironment(const std::string& env) {
|
||||
prefs_->SetString(prefs::kBraveVPNEEnvironment, env);
|
||||
profile_prefs_->SetString(prefs::kBraveVPNEEnvironment, env);
|
||||
purchased_state_.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,10 @@ class BraveBrowserCommandControllerTest;
|
||||
|
||||
namespace brave_vpn {
|
||||
|
||||
constexpr char kNewUserReturningHistogramName[] = "Brave.VPN.NewUserReturning";
|
||||
constexpr char kDaysInMonthUsedHistogramName[] = "Brave.VPN.DaysInMonthUsed";
|
||||
constexpr char kLastUsageTimeHistogramName[] = "Brave.VPN.LastUsageTime";
|
||||
|
||||
// This class is used by desktop and android.
|
||||
// However, it includes desktop specific impls and it's hidden
|
||||
// by IS_ANDROID ifdef.
|
||||
@@ -65,7 +69,8 @@ class BraveVpnService :
|
||||
public:
|
||||
BraveVpnService(
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
|
||||
PrefService* prefs,
|
||||
PrefService* local_prefs,
|
||||
PrefService* profile_prefs,
|
||||
base::RepeatingCallback<mojo::PendingRemote<skus::mojom::SkusService>()>
|
||||
skus_service_getter);
|
||||
~BraveVpnService() override;
|
||||
@@ -158,8 +163,20 @@ class BraveVpnService :
|
||||
const std::string& payments_environment,
|
||||
const std::string& monthly_pass);
|
||||
|
||||
// new_usage should be set to true if a new VPN connection was just
|
||||
// established.
|
||||
void RecordP3A(bool new_usage);
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
void RecordAndroidBackgroundP3A(int64_t session_start_time_ms,
|
||||
int64_t session_end_time_ms);
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class BraveVPNServiceTest;
|
||||
|
||||
void InitP3A();
|
||||
void OnP3AInterval();
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
friend class ::BraveAppMenuBrowserTest;
|
||||
friend class ::BraveBrowserCommandControllerTest;
|
||||
@@ -253,7 +270,8 @@ class BraveVpnService :
|
||||
const std::string& domain,
|
||||
const std::string& credential_as_cookie);
|
||||
|
||||
raw_ptr<PrefService> prefs_ = nullptr;
|
||||
raw_ptr<PrefService> local_prefs_ = nullptr;
|
||||
raw_ptr<PrefService> profile_prefs_ = nullptr;
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
std::vector<mojom::Region> regions_;
|
||||
std::unique_ptr<Hostname> hostname_;
|
||||
@@ -283,6 +301,7 @@ class BraveVpnService :
|
||||
mojo::RemoteSet<mojom::ServiceObserver> observers_;
|
||||
api_request_helper::APIRequestHelper api_request_helper_;
|
||||
std::string skus_credential_;
|
||||
base::RepeatingTimer p3a_timer_;
|
||||
base::WeakPtrFactory<BraveVpnService> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "base/json/json_writer.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "brave/components/brave_vpn/brave_vpn_service.h"
|
||||
#include "brave/components/brave_vpn/brave_vpn_service_helper.h"
|
||||
@@ -170,14 +171,20 @@ class TestBraveVPNServiceObserver : public mojom::ServiceObserver {
|
||||
|
||||
class BraveVPNServiceTest : public testing::Test {
|
||||
public:
|
||||
BraveVPNServiceTest() {
|
||||
BraveVPNServiceTest()
|
||||
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
|
||||
scoped_feature_list_.InitWithFeatures(
|
||||
{skus::features::kSkusFeature, features::kBraveVPN}, {});
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
skus::RegisterProfilePrefs(pref_service_.registry());
|
||||
prefs::RegisterProfilePrefs(pref_service_.registry());
|
||||
base::Time future_mock_time;
|
||||
if (base::Time::FromString("2023-01-04", &future_mock_time)) {
|
||||
task_environment_.AdvanceClock(future_mock_time - base::Time::Now());
|
||||
}
|
||||
skus::RegisterProfilePrefs(profile_pref_service_.registry());
|
||||
prefs::RegisterProfilePrefs(profile_pref_service_.registry());
|
||||
prefs::RegisterLocalStatePrefs(local_pref_service_.registry());
|
||||
shared_url_loader_factory_ =
|
||||
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
|
||||
&url_loader_factory_);
|
||||
@@ -185,17 +192,17 @@ class BraveVPNServiceTest : public testing::Test {
|
||||
&BraveVPNServiceTest::Interceptor, base::Unretained(this)));
|
||||
// Setup required for SKU (dependency of VPN)
|
||||
skus_service_ = std::make_unique<skus::SkusServiceImpl>(
|
||||
&pref_service_, url_loader_factory_.GetSafeWeakWrapper());
|
||||
&profile_pref_service_, url_loader_factory_.GetSafeWeakWrapper());
|
||||
ResetVpnService();
|
||||
}
|
||||
|
||||
void ResetVpnService() {
|
||||
service_ = std::make_unique<BraveVpnService>(
|
||||
url_loader_factory_.GetSafeWeakWrapper(), &pref_service_,
|
||||
url_loader_factory_.GetSafeWeakWrapper(), &local_pref_service_,
|
||||
&profile_pref_service_,
|
||||
base::BindRepeating(&BraveVPNServiceTest::GetSkusService,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
PrefService* prefs() { return &pref_service_; }
|
||||
mojo::PendingRemote<skus::mojom::SkusService> GetSkusService() {
|
||||
if (!skus_service_) {
|
||||
return mojo::PendingRemote<skus::mojom::SkusService>();
|
||||
@@ -314,6 +321,7 @@ class BraveVPNServiceTest : public testing::Test {
|
||||
}
|
||||
|
||||
#endif
|
||||
void RecordP3A(bool new_usage) { service_->RecordP3A(new_usage); }
|
||||
|
||||
std::string GetCurrentEnvironment() {
|
||||
return service_->GetCurrentEnvironment();
|
||||
@@ -481,7 +489,7 @@ class BraveVPNServiceTest : public testing::Test {
|
||||
auto testing_payload = GenerateTestingCreds(domain, active_subscription);
|
||||
base::Value state(base::Value::Type::DICT);
|
||||
state.SetStringKey("skus:" + env, testing_payload);
|
||||
prefs()->Set(skus::prefs::kSkusState, std::move(state));
|
||||
profile_pref_service_.Set(skus::prefs::kSkusState, std::move(state));
|
||||
SetInterceptorResponse(GetRegionsData());
|
||||
return domain;
|
||||
}
|
||||
@@ -499,12 +507,14 @@ class BraveVPNServiceTest : public testing::Test {
|
||||
std::string https_response_;
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
content::BrowserTaskEnvironment task_environment_;
|
||||
sync_preferences::TestingPrefServiceSyncable pref_service_;
|
||||
sync_preferences::TestingPrefServiceSyncable profile_pref_service_;
|
||||
sync_preferences::TestingPrefServiceSyncable local_pref_service_;
|
||||
std::unique_ptr<skus::SkusServiceImpl> skus_service_;
|
||||
std::unique_ptr<BraveVpnService> service_;
|
||||
network::TestURLLoaderFactory url_loader_factory_;
|
||||
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
|
||||
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
|
||||
base::HistogramTester histogram_tester_;
|
||||
};
|
||||
|
||||
TEST(BraveVPNFeatureTest, FeatureTest) {
|
||||
@@ -698,6 +708,7 @@ TEST_F(BraveVPNServiceTest, ConnectionStateUpdateWithPurchasedStateTest) {
|
||||
UpdateAndNotifyConnectionStateChange(ConnectionState::CONNECTED);
|
||||
EXPECT_NE(ConnectionState::CONNECTED, connection_state());
|
||||
}
|
||||
|
||||
TEST_F(BraveVPNServiceTest, ConnectionInfoTest) {
|
||||
// Having skus_credential is pre-requisite before try connecting.
|
||||
skus_credential() = "test_credentials";
|
||||
@@ -924,8 +935,8 @@ TEST_F(BraveVPNServiceTest, CheckInitialPurchasedStateTest) {
|
||||
EXPECT_EQ(PurchasedState::NOT_PURCHASED, GetPurchasedStateSync());
|
||||
|
||||
// Dirty region list prefs to pretend it's already cached.
|
||||
pref_service_.Set(prefs::kBraveVPNRegionList,
|
||||
base::Value(base::Value::Type::LIST));
|
||||
profile_pref_service_.Set(prefs::kBraveVPNRegionList,
|
||||
base::Value(base::Value::Type::LIST));
|
||||
ResetVpnService();
|
||||
EXPECT_EQ(PurchasedState::LOADING, GetPurchasedStateSync());
|
||||
}
|
||||
@@ -1038,4 +1049,52 @@ TEST_F(BraveVPNServiceTest, LoadPurchasedStateForAnotherEnv) {
|
||||
EXPECT_EQ(GetCurrentEnvironment(), skus::kEnvStaging);
|
||||
}
|
||||
|
||||
TEST_F(BraveVPNServiceTest, NewUserReturningMetric) {
|
||||
RecordP3A(false);
|
||||
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 0, 2);
|
||||
|
||||
task_environment_.FastForwardBy(base::Days(1));
|
||||
RecordP3A(true);
|
||||
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 2, 1);
|
||||
|
||||
task_environment_.FastForwardBy(base::Days(1));
|
||||
RecordP3A(true);
|
||||
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 3, 1);
|
||||
|
||||
task_environment_.FastForwardBy(base::Days(6));
|
||||
histogram_tester_.ExpectBucketCount(kNewUserReturningHistogramName, 1, 1);
|
||||
}
|
||||
|
||||
TEST_F(BraveVPNServiceTest, DaysInMonthUsedMetric) {
|
||||
RecordP3A(false);
|
||||
histogram_tester_.ExpectTotalCount(kDaysInMonthUsedHistogramName, 0);
|
||||
|
||||
RecordP3A(true);
|
||||
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 1, 1);
|
||||
|
||||
task_environment_.FastForwardBy(base::Days(1));
|
||||
RecordP3A(true);
|
||||
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 2, 1);
|
||||
task_environment_.FastForwardBy(base::Days(1));
|
||||
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 2, 2);
|
||||
|
||||
RecordP3A(true);
|
||||
task_environment_.FastForwardBy(base::Days(30));
|
||||
histogram_tester_.ExpectBucketCount(kDaysInMonthUsedHistogramName, 0, 1);
|
||||
}
|
||||
|
||||
TEST_F(BraveVPNServiceTest, LastUsageTimeMetric) {
|
||||
histogram_tester_.ExpectTotalCount(kLastUsageTimeHistogramName, 0);
|
||||
|
||||
RecordP3A(true);
|
||||
histogram_tester_.ExpectBucketCount(kLastUsageTimeHistogramName, 1, 1);
|
||||
|
||||
task_environment_.AdvanceClock(base::Days(10));
|
||||
RecordP3A(true);
|
||||
histogram_tester_.ExpectBucketCount(kLastUsageTimeHistogramName, 1, 2);
|
||||
task_environment_.AdvanceClock(base::Days(10));
|
||||
RecordP3A(false);
|
||||
histogram_tester_.ExpectBucketCount(kLastUsageTimeHistogramName, 2, 1);
|
||||
}
|
||||
|
||||
} // namespace brave_vpn
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "brave/components/brave_vpn/pref_names.h"
|
||||
|
||||
#include "brave/components/p3a_utils/feature_usage.h"
|
||||
#include "brave/components/skus/browser/skus_utils.h"
|
||||
#include "components/prefs/pref_registry_simple.h"
|
||||
|
||||
@@ -32,6 +33,12 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
|
||||
skus::GetDefaultEnvironment());
|
||||
}
|
||||
|
||||
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
|
||||
p3a_utils::RegisterFeatureUsagePrefs(
|
||||
registry, kBraveVPNFirstUseTime, kBraveVPNLastUseTime,
|
||||
kBraveVPNUsedSecondDay, kBraveVPNDaysInMonthUsed);
|
||||
}
|
||||
|
||||
} // namespace prefs
|
||||
|
||||
} // namespace brave_vpn
|
||||
|
||||
@@ -27,7 +27,14 @@ extern const char kBraveVPNPurchaseTokenAndroid[];
|
||||
extern const char kBraveVPNPackageAndroid[];
|
||||
#endif
|
||||
|
||||
constexpr char kBraveVPNFirstUseTime[] = "brave.brave_vpn.first_use_time";
|
||||
constexpr char kBraveVPNLastUseTime[] = "brave.brave_vpn.last_use_time";
|
||||
constexpr char kBraveVPNUsedSecondDay[] = "brave.brave_vpn.used_second_day";
|
||||
constexpr char kBraveVPNDaysInMonthUsed[] =
|
||||
"brave.brave_vpn.days_in_month_used";
|
||||
|
||||
void RegisterProfilePrefs(PrefRegistrySimple* registry);
|
||||
void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
|
||||
|
||||
} // namespace prefs
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ constexpr inline auto kCollectedHistograms =
|
||||
"Brave.Sync.Status.2",
|
||||
"Brave.Sync.ProgressTokenEverReset",
|
||||
"Brave.Uptime.BrowserOpenMinutes",
|
||||
"Brave.VPN.NewUserReturning",
|
||||
"Brave.VPN.DaysInMonthUsed",
|
||||
"Brave.VPN.LastUsageTime",
|
||||
"Brave.Wallet.DefaultSolanaWalletSetting",
|
||||
"Brave.Wallet.DefaultWalletSetting",
|
||||
"Brave.Wallet.KeyringCreated",
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
|
||||
namespace p3a_utils {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kDaysInMonthBuckets[] = {0, 1, 2, 5, 10, 15, 20, 100};
|
||||
|
||||
} // namespace
|
||||
|
||||
void RegisterFeatureUsagePrefs(PrefRegistrySimple* registry,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name,
|
||||
@@ -36,14 +42,23 @@ void RegisterFeatureUsagePrefs(PrefRegistrySimple* registry,
|
||||
void RecordFeatureUsage(PrefService* prefs,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name) {
|
||||
RecordFeatureUsage(prefs, first_use_time_pref_name, last_use_time_pref_name,
|
||||
base::Time::Now());
|
||||
}
|
||||
|
||||
void RecordFeatureUsage(PrefService* prefs,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name,
|
||||
const base::Time& last_new_use_time) {
|
||||
DCHECK(prefs);
|
||||
DCHECK(first_use_time_pref_name);
|
||||
DCHECK(last_use_time_pref_name);
|
||||
DCHECK(!last_new_use_time.is_null());
|
||||
|
||||
base::Time now_midnight = base::Time::Now().LocalMidnight();
|
||||
prefs->SetTime(last_use_time_pref_name, now_midnight);
|
||||
base::Time new_time_midnight = last_new_use_time.LocalMidnight();
|
||||
prefs->SetTime(last_use_time_pref_name, new_time_midnight);
|
||||
if (prefs->GetTime(first_use_time_pref_name).is_null()) {
|
||||
prefs->SetTime(first_use_time_pref_name, now_midnight);
|
||||
prefs->SetTime(first_use_time_pref_name, new_time_midnight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +87,8 @@ void RecordFeatureNewUserReturning(PrefService* prefs,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* used_second_day_pref_name,
|
||||
const char* histogram_name) {
|
||||
const char* histogram_name,
|
||||
bool write_to_histogram) {
|
||||
DCHECK(prefs);
|
||||
DCHECK(first_use_time_pref_name);
|
||||
DCHECK(last_use_time_pref_name);
|
||||
@@ -81,6 +97,7 @@ void RecordFeatureNewUserReturning(PrefService* prefs,
|
||||
|
||||
base::Time last_use_time = prefs->GetTime(last_use_time_pref_name);
|
||||
base::Time first_use_time = prefs->GetTime(first_use_time_pref_name);
|
||||
|
||||
int answer = 0;
|
||||
if (!first_use_time.is_null()) {
|
||||
// If the first use time was set, we can assume that
|
||||
@@ -109,14 +126,17 @@ void RecordFeatureNewUserReturning(PrefService* prefs,
|
||||
answer = 4;
|
||||
}
|
||||
}
|
||||
base::UmaHistogramExactLinear(histogram_name, answer, 5);
|
||||
if (write_to_histogram) {
|
||||
base::UmaHistogramExactLinear(histogram_name, answer, 5);
|
||||
}
|
||||
}
|
||||
|
||||
void RecordFeatureDaysInMonthUsed(PrefService* prefs,
|
||||
bool is_add,
|
||||
const base::Time& add_date,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* days_in_month_used_pref_name,
|
||||
const char* histogram_name) {
|
||||
const char* histogram_name,
|
||||
bool write_to_histogram) {
|
||||
DCHECK(prefs);
|
||||
DCHECK(last_use_time_pref_name);
|
||||
DCHECK(days_in_month_used_pref_name);
|
||||
@@ -126,13 +146,25 @@ void RecordFeatureDaysInMonthUsed(PrefService* prefs,
|
||||
// Don't report if feature was never used
|
||||
return;
|
||||
}
|
||||
// How many days was the feature used in the last month?
|
||||
constexpr int buckets[] = {0, 1, 2, 5, 10, 15, 20, 100};
|
||||
MonthlyStorage storage(prefs, days_in_month_used_pref_name);
|
||||
if (is_add) {
|
||||
storage.ReplaceTodaysValueIfGreater(1);
|
||||
if (!add_date.is_null()) {
|
||||
storage.ReplaceIfGreaterForDate(add_date, 1);
|
||||
}
|
||||
RecordToHistogramBucket(histogram_name, buckets, storage.GetMonthlySum());
|
||||
if (write_to_histogram) {
|
||||
RecordToHistogramBucket(histogram_name, kDaysInMonthBuckets,
|
||||
storage.GetMonthlySum());
|
||||
}
|
||||
}
|
||||
|
||||
void RecordFeatureDaysInMonthUsed(PrefService* prefs,
|
||||
bool is_add,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* days_in_month_used_pref_name,
|
||||
const char* histogram_name,
|
||||
bool write_to_histogram) {
|
||||
RecordFeatureDaysInMonthUsed(
|
||||
prefs, is_add ? base::Time::Now() : base::Time(), last_use_time_pref_name,
|
||||
days_in_month_used_pref_name, histogram_name, write_to_histogram);
|
||||
}
|
||||
|
||||
void RecordFeatureLastUsageTimeMetric(PrefService* prefs,
|
||||
|
||||
@@ -31,6 +31,12 @@ void RecordFeatureUsage(PrefService* prefs,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name);
|
||||
|
||||
// Updates the first/last use time preferences using an external timestamp;
|
||||
void RecordFeatureUsage(PrefService* prefs,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name,
|
||||
const base::Time& last_new_use_time);
|
||||
|
||||
// Assists in migrating existing external last use timestamps that existed
|
||||
// before this P3A utility was created.
|
||||
void MaybeRecordFeatureExistingUsageTimestamp(
|
||||
@@ -57,7 +63,8 @@ void RecordFeatureNewUserReturning(PrefService* prefs,
|
||||
const char* first_use_time_pref_name,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* used_second_day_pref_name,
|
||||
const char* histogram_name);
|
||||
const char* histogram_name,
|
||||
bool write_to_histogram = true);
|
||||
|
||||
// Records the DaysInMonthUsed metric. Will not report if feature never used.
|
||||
//
|
||||
@@ -76,7 +83,17 @@ void RecordFeatureDaysInMonthUsed(PrefService* prefs,
|
||||
bool is_add,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* days_in_month_used_pref_name,
|
||||
const char* histogram_name);
|
||||
const char* histogram_name,
|
||||
bool write_to_histogram = true);
|
||||
|
||||
// Adds feature usage to monthly storage for a provided date,
|
||||
// and records the DaysInMonthUsed metric.
|
||||
void RecordFeatureDaysInMonthUsed(PrefService* prefs,
|
||||
const base::Time& add_date,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* days_in_month_used_pref_name,
|
||||
const char* histogram_name,
|
||||
bool write_to_histogram = true);
|
||||
|
||||
// Records the LastUsageTime metric. Will not report if feature never used.
|
||||
//
|
||||
@@ -84,12 +101,12 @@ void RecordFeatureDaysInMonthUsed(PrefService* prefs,
|
||||
// feature?
|
||||
//
|
||||
// Answers:
|
||||
// 1. This week
|
||||
// 2. 1 week ago
|
||||
// 3. 2 weeks ago
|
||||
// 4. 3 weeks ago
|
||||
// 5. A month ago
|
||||
// 6. Over a month ago
|
||||
// 1. 0 - 6 days ago (less than a week)
|
||||
// 2. 7 - 13 days ago (one week ago or more)
|
||||
// 3. 14 - 20 days ago (two weeks ago or more)
|
||||
// 4. 21 - 27 days ago (three weeks ago or more)
|
||||
// 5. 28 - 59 days ago (four weeks ago or more)
|
||||
// 6. 60 days ago or more (two months ago or more)
|
||||
void RecordFeatureLastUsageTimeMetric(PrefService* prefs,
|
||||
const char* last_use_time_pref_name,
|
||||
const char* histogram_name);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include "base/ranges/algorithm.h"
|
||||
#include "base/time/clock.h"
|
||||
#include "base/time/default_clock.h"
|
||||
#include "base/values.h"
|
||||
@@ -71,6 +72,24 @@ void TimePeriodStorage::ReplaceTodaysValueIfGreater(uint64_t value) {
|
||||
Save();
|
||||
}
|
||||
|
||||
void TimePeriodStorage::ReplaceIfGreaterForDate(const base::Time& date,
|
||||
uint64_t value) {
|
||||
FilterToPeriod();
|
||||
base::Time date_mn = date.LocalMidnight();
|
||||
std::list<DailyValue>::iterator day_insert_it = base::ranges::find_if(
|
||||
daily_values_.begin(), daily_values_.end(),
|
||||
[date_mn](const DailyValue& val) { return val.day <= date_mn; });
|
||||
if (day_insert_it != daily_values_.end() && day_insert_it->day == date_mn) {
|
||||
// update daily value if it exists for date
|
||||
if (value > day_insert_it->value) {
|
||||
day_insert_it->value = value;
|
||||
}
|
||||
} else {
|
||||
daily_values_.insert(day_insert_it, {date_mn, value});
|
||||
}
|
||||
Save();
|
||||
}
|
||||
|
||||
uint64_t TimePeriodStorage::GetPeriodSum() const {
|
||||
// We record only value for last N days.
|
||||
const base::Time n_days_ago = clock_->Now() - base::Days(period_days_);
|
||||
|
||||
@@ -39,6 +39,7 @@ class TimePeriodStorage {
|
||||
void AddDelta(uint64_t delta);
|
||||
void SubDelta(uint64_t delta);
|
||||
void ReplaceTodaysValueIfGreater(uint64_t value);
|
||||
void ReplaceIfGreaterForDate(const base::Time& date, uint64_t value);
|
||||
uint64_t GetPeriodSum() const;
|
||||
uint64_t GetHighestValueInPeriod() const;
|
||||
bool IsOnePeriodPassed() const;
|
||||
|
||||
@@ -214,3 +214,29 @@ TEST_F(TimePeriodStorageTest, GetsHighestValueInWeekFromReplacement) {
|
||||
// Sanity check disparate days were not replaced
|
||||
EXPECT_EQ(state_->GetPeriodSum(), high_value + low_value);
|
||||
}
|
||||
|
||||
TEST_F(TimePeriodStorageTest, ReplaceIfGreaterForDate) {
|
||||
InitStorage(30);
|
||||
|
||||
state_->AddDelta(4);
|
||||
clock_->Advance(base::Days(1));
|
||||
state_->AddDelta(2);
|
||||
clock_->Advance(base::Days(1));
|
||||
state_->AddDelta(1);
|
||||
clock_->Advance(base::Days(1));
|
||||
|
||||
// should replace
|
||||
state_->ReplaceIfGreaterForDate(clock_->Now() - base::Days(2), 3);
|
||||
// should not replace
|
||||
state_->ReplaceIfGreaterForDate(clock_->Now() - base::Days(3), 3);
|
||||
|
||||
EXPECT_EQ(state_->GetPeriodSum(), 8U);
|
||||
|
||||
// should insert new daily value
|
||||
state_->ReplaceIfGreaterForDate(clock_->Now() - base::Days(4), 3);
|
||||
EXPECT_EQ(state_->GetPeriodSum(), 11U);
|
||||
|
||||
// should store, but should not be in sum because it's too old
|
||||
state_->ReplaceIfGreaterForDate(clock_->Now() - base::Days(31), 10);
|
||||
EXPECT_EQ(state_->GetPeriodSum(), 11U);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user