blob: c14bfc51712ef71c77427cdef378deb5a1ebf066 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/first_run/location_permissions_field_trial.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
#include "ios/chrome/browser/first_run/first_run.h"
#include "ios/chrome/browser/ui/first_run/ios_first_run_field_trials.h"
#include "ios/chrome/browser/ui/ui_feature_flags.h"
#include "ios/chrome/common/channel_info.h"
namespace {
// String local state preference with the name of the assigned trial group.
// Empty if no group has been assigned yet.
const char kTrialGroupPrefName[] = "location_permissions.trial_group";
// Group names for the location permissions trial.
const char kLocationFirstRunModalGroup[] = "LocationFirstRunModal";
const char kLocationRemoveFirstRunPromptGroup[] =
"LocationRemoveFirstRunPrompt";
const char kDisabledGroup[] = "Disabled";
const char kDefaultGroup[] = "Default";
// Experiment IDs defined for the above field trial groups.
const variations::VariationID kDefaultTrialID = 3329335;
const variations::VariationID kDisabledTrialID = 3329336;
const variations::VariationID kLocationRemoveFirstRunPromptTrialID = 3329337;
const variations::VariationID kLocationFirstRunModalTrialID = 3329338;
// Default local state pref value.
const int kDefaultPrefValue = -1;
} // namespace
namespace location_permissions_field_trial {
// Sets the feature state based on the trial group. Defaults to disabled.
void SetFeatureState(const std::string& group_name,
base::FeatureList* feature_list,
base::FieldTrial* trial) {
base::FeatureList::OverrideState feature_state =
base::FeatureList::OVERRIDE_DISABLE_FEATURE;
if (group_name == kLocationFirstRunModalGroup ||
group_name == kLocationRemoveFirstRunPromptGroup) {
feature_state = base::FeatureList::OVERRIDE_ENABLE_FEATURE;
}
feature_list->RegisterFieldTrialOverride(kLocationPermissionsPrompt.name,
feature_state, trial);
}
bool IsInFirstRunModalGroup() {
return base::FeatureList::IsEnabled(kLocationPermissionsPrompt) &&
base::FieldTrialList::FindFullName(kLocationPermissionsPrompt.name) ==
kLocationFirstRunModalGroup;
}
bool IsInRemoveFirstRunPromptGroup() {
return base::FeatureList::IsEnabled(kLocationPermissionsPrompt) &&
base::FieldTrialList::FindFullName(kLocationPermissionsPrompt.name) ==
kLocationRemoveFirstRunPromptGroup;
}
// Creates a trial for the first run (when there is no variations seed) if
// necessary and enables the feature based on the randomly selected trial group.
// Returns the group number.
int CreateFirstRunTrial(
base::FieldTrial::EntropyProvider const& low_entropy_provider,
base::FeatureList* feature_list) {
int fre_modal_enabled_percent;
int remove_fre_prompt_enabled_percent;
int disabled_percent;
int default_percent;
switch (GetChannel()) {
case version_info::Channel::UNKNOWN:
case version_info::Channel::CANARY:
case version_info::Channel::DEV:
case version_info::Channel::BETA:
fre_modal_enabled_percent = 33;
remove_fre_prompt_enabled_percent = 33;
disabled_percent = 33;
default_percent = 1;
break;
case version_info::Channel::STABLE:
fre_modal_enabled_percent = 15;
remove_fre_prompt_enabled_percent = 15;
disabled_percent = 15;
default_percent = 55;
break;
}
// Set up the trial and groups.
FirstRunFieldTrialConfig config(kLocationPermissionsPrompt.name);
config.AddGroup(kDefaultGroup, kDefaultTrialID, default_percent);
config.AddGroup(kLocationRemoveFirstRunPromptGroup,
kLocationRemoveFirstRunPromptTrialID,
remove_fre_prompt_enabled_percent);
config.AddGroup(kLocationFirstRunModalGroup, kLocationFirstRunModalTrialID,
fre_modal_enabled_percent);
// Add disabled group last to match internal implementation in field_trial.cc
config.AddGroup(kDisabledGroup, kDisabledTrialID, disabled_percent);
DCHECK_EQ(100, config.GetTotalProbability());
scoped_refptr<base::FieldTrial> trial =
config.CreateOneTimeRandomizedTrial(kDisabledGroup, low_entropy_provider);
// Finalize the group choice and activates the trial - similar to a variation
// config that's marked with |starts_active| true. This is required for
// studies that register variation ids, so they don't reveal extra information
// beyond the low-entropy source.
int group = trial->group();
const std::string& group_name = trial->group_name();
SetFeatureState(group_name, feature_list, trial.get());
return group;
}
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(kTrialGroupPrefName, kDefaultPrefValue);
}
void Create(const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list,
PrefService* local_state) {
int trial_group = local_state->GetInteger(kTrialGroupPrefName);
if (trial_group == kDefaultPrefValue && !FirstRun::IsChromeFirstRun()) {
// Do not bucket existing users that have not been already been grouped. The
// experiment wants to only add users who have not seen the First Run
// Experience yet.
return;
}
// Create trial and group user for the first time, or tag users again to
// ensure the experiment can be used to filter UMA metrics.
trial_group = CreateFirstRunTrial(low_entropy_provider, feature_list);
// Persist the assigned group for subsequent runs.
local_state->SetInteger(kTrialGroupPrefName, trial_group);
}
} // namespace location_permissions_field_trial