blob: bc2be7f8948381bd06eb62d1f7d5f50860d78f69 [file] [log] [blame]
// Copyright 2018 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.
#include "chrome/browser/ui/webui/welcome/nux_helper.h"
#include <string>
#include <vector>
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/policy/browser_signin_policy_handler.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/ntp_features.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/webui/welcome/nux/constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_service.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#if defined(OS_MACOSX)
#include "base/enterprise_util.h"
#endif // defined(OS_MACOSX)
namespace nux {
bool CanShowGoogleAppModule(const policy::PolicyMap& policies) {
const base::Value* bookmark_bar_enabled_value =
policies.GetValue(policy::key::kBookmarkBarEnabled);
if (bookmark_bar_enabled_value && !bookmark_bar_enabled_value->GetBool()) {
return false;
}
const base::Value* edit_bookmarks_value =
policies.GetValue(policy::key::kEditBookmarksEnabled);
if (edit_bookmarks_value && !edit_bookmarks_value->GetBool()) {
return false;
}
return true;
}
bool CanShowGoogleAppModuleForTesting(const policy::PolicyMap& policies) {
return CanShowGoogleAppModule(policies);
}
bool CanShowNTPBackgroundModule(const policy::PolicyMap& policies,
Profile* profile) {
// We can't set the background if the NTP is something other than Google.
return !policies.GetValue(policy::key::kNewTabPageLocation) &&
search::DefaultSearchProviderIsGoogle(profile);
}
bool CanShowNTPBackgroundModuleForTesting(const policy::PolicyMap& policies,
Profile* profile) {
return CanShowNTPBackgroundModule(policies, profile);
}
bool CanShowSetDefaultModule(const policy::PolicyMap& policies) {
const base::Value* set_default_value =
policies.GetValue(policy::key::kDefaultBrowserSettingEnabled);
return !set_default_value || set_default_value->GetBool();
}
bool CanShowSetDefaultModuleForTesting(const policy::PolicyMap& policies) {
return CanShowSetDefaultModule(policies);
}
bool CanShowSigninModule(const policy::PolicyMap& policies) {
const base::Value* browser_signin_value =
policies.GetValue(policy::key::kBrowserSignin);
if (!browser_signin_value)
return true;
int int_browser_signin_value;
bool success = browser_signin_value->GetAsInteger(&int_browser_signin_value);
DCHECK(success);
return static_cast<policy::BrowserSigninMode>(int_browser_signin_value) !=
policy::BrowserSigninMode::kDisabled;
}
bool CanShowSigninModuleForTesting(const policy::PolicyMap& policies) {
return CanShowSigninModule(policies);
}
// This feature flag is used to force the feature to be turned on for non-win
// and non-branded builds, like with tests or development on other platforms.
const base::Feature kNuxOnboardingForceEnabled = {
"NuxOnboardingForceEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
// The value of these FeatureParam values should be a comma-delimited list
// of element names whitelisted in the MODULES_WHITELIST list, defined in
// chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js
const base::FeatureParam<std::string> kNuxOnboardingForceEnabledNewUserModules =
{&kNuxOnboardingForceEnabled, "new-user-modules",
"nux-google-apps,nux-ntp-background,nux-set-as-default,"
"signin-view"};
const base::FeatureParam<std::string>
kNuxOnboardingForceEnabledReturningUserModules = {
&kNuxOnboardingForceEnabled, "returning-user-modules",
"nux-set-as-default"};
// Onboarding experiments depend on Google being the default search provider.
bool CanExperimentWithVariations(Profile* profile) {
return search::DefaultSearchProviderIsGoogle(profile);
}
// Must match study name in configs.
const char kNuxOnboardingStudyName[] = "NaviOnboarding";
std::string GetOnboardingGroup(Profile* profile) {
if (!CanExperimentWithVariations(profile)) {
// If we cannot run any variations, we bucket the users into a separate
// synthetic group that we will ignore data for.
return "NaviNoVariationSynthetic";
}
// We need to use |base::GetFieldTrialParamValue| instead of
// |base::FeatureParam| because our control group needs a custom value for
// this param.
return base::GetFieldTrialParamValue(kNuxOnboardingStudyName,
"onboarding-group");
}
bool IsNuxOnboardingEnabled(Profile* profile) {
if (base::FeatureList::IsEnabled(nux::kNuxOnboardingForceEnabled)) {
return true;
}
#if defined(GOOGLE_CHROME_BUILD)
#if defined(OS_MACOSX)
return !base::IsMachineExternallyManaged();
#endif // defined(OS_MACOSX)
#if defined(OS_WIN)
// To avoid diluting data collection, existing users should not be assigned
// an onboarding group. So, |prefs::kNaviOnboardGroup| is used to
// short-circuit the feature checks below.
PrefService* prefs = profile->GetPrefs();
if (!prefs) {
return false;
}
std::string onboard_group = prefs->GetString(prefs::kNaviOnboardGroup);
if (onboard_group.empty()) {
// Users who onboarded before Navi or are part of an enterprise.
return false;
}
if (!CanExperimentWithVariations(profile)) {
return true; // Default Navi behavior.
}
// User will be tied to their original onboarding group, even after
// experiment ends.
ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
"NaviOnboardingSynthetic", onboard_group);
if (base::FeatureList::IsEnabled(nux::kNuxOnboardingFeature)) {
return true;
}
#endif // defined(OS_WIN)
#endif // defined(GOOGLE_CHROME_BUILD)
return false;
}
const policy::PolicyMap& GetPoliciesFromProfile(Profile* profile) {
policy::ProfilePolicyConnector* profile_connector =
profile->GetProfilePolicyConnector();
DCHECK(profile_connector);
return profile_connector->policy_service()->GetPolicies(
policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
}
std::vector<std::string> GetAvailableModules(Profile* profile) {
const policy::PolicyMap& policies = GetPoliciesFromProfile(profile);
std::vector<std::string> available_modules;
if (CanShowGoogleAppModule(policies))
available_modules.push_back("nux-google-apps");
if (CanShowNTPBackgroundModule(policies, profile))
available_modules.push_back("nux-ntp-background");
if (CanShowSetDefaultModule(policies))
available_modules.push_back("nux-set-as-default");
if (CanShowSigninModule(policies))
available_modules.push_back("signin-view");
return available_modules;
}
bool DoesOnboardingHaveModulesToShow(Profile* profile) {
const base::Value* force_ephemeral_profiles_value =
GetPoliciesFromProfile(profile).GetValue(
policy::key::kForceEphemeralProfiles);
// Modules won't have a lasting effect if profile is ephemeral.
if (force_ephemeral_profiles_value &&
force_ephemeral_profiles_value->GetBool()) {
return false;
}
return !GetAvailableModules(profile).empty();
}
std::string FilterModules(const std::string& requested_modules,
const std::vector<std::string>& available_modules) {
std::vector<std::string> requested_list = base::SplitString(
requested_modules, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::vector<std::string> filtered_modules;
std::copy_if(requested_list.begin(), requested_list.end(),
std::back_inserter(filtered_modules),
[available_modules](std::string module) {
return !module.empty() &&
base::ContainsValue(available_modules, module);
});
return base::JoinString(filtered_modules, ",");
}
base::DictionaryValue GetNuxOnboardingModules(Profile* profile) {
// This function should not be called when nux onboarding feature is not on.
DCHECK(nux::IsNuxOnboardingEnabled(profile));
std::string new_user_modules = kDefaultNewUserModules;
std::string returning_user_modules = kDefaultReturningUserModules;
if (base::FeatureList::IsEnabled(nux::kNuxOnboardingForceEnabled)) {
new_user_modules = kNuxOnboardingForceEnabledNewUserModules.Get();
returning_user_modules =
kNuxOnboardingForceEnabledReturningUserModules.Get();
} else if (CanExperimentWithVariations(profile)) {
new_user_modules = kNuxOnboardingNewUserModules.Get();
returning_user_modules = kNuxOnboardingReturningUserModules.Get();
}
std::vector<std::string> available_modules = GetAvailableModules(profile);
base::DictionaryValue modules;
modules.SetString("new-user",
FilterModules(new_user_modules, available_modules));
modules.SetString("returning-user",
FilterModules(returning_user_modules, available_modules));
return modules;
}
} // namespace nux