blob: 0f964dc3e9bdab53629afc349b97dc2783c01fc6 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/startup/default_browser_prompt.h"
#include <limits>
#include <string>
#include "base/check_is_test.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/startup/default_browser_infobar_delegate.h"
#include "chrome/browser/ui/startup/default_browser_prompt_manager.h"
#include "chrome/browser/ui/startup/default_browser_prompt_trial.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/common/pref_names.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/visibility.h"
#include "content/public/browser/web_contents.h"
namespace {
void ShowPrompt() {
// Show the default browser request prompt in the most recently active,
// visible, tabbed browser. Do not show the prompt if no such browser exists.
for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
// |browser| may be null in UI tests. Also, don't show the prompt in an app
// window, which is not meant to be treated as a Chrome window. Only show in
// a normal, tabbed browser.
if (browser && !browser->is_type_normal())
continue;
// In ChromeBot tests, there might be a race. This line appears to get
// called during shutdown and the active web contents can be nullptr.
content::WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (!web_contents ||
web_contents->GetVisibility() != content::Visibility::VISIBLE) {
continue;
}
chrome::DefaultBrowserInfoBarDelegate::Create(
infobars::ContentInfoBarManager::FromWebContents(web_contents),
browser->profile());
break;
}
}
// Do not show the prompt if "suppress_default_browser_prompt_for_version" in
// the initial preferences is set to the current version.
bool ShouldShowDefaultBrowserPromptForCurrentVersion() {
const std::string disable_version_string =
g_browser_process->local_state()->GetString(
prefs::kBrowserSuppressDefaultBrowserPrompt);
const base::Version disable_version(disable_version_string);
DCHECK(disable_version_string.empty() || disable_version.IsValid());
return !(disable_version.IsValid() &&
disable_version == version_info::GetVersion());
}
// Returns true if the default browser prompt should be shown if Chrome is not
// the user's default browser.
bool ShouldShowDefaultBrowserPrompt(Profile* profile) {
// Do not show if the user has previously declined the prompt.
int64_t last_dismissed_value =
profile->GetPrefs()->GetInt64(prefs::kDefaultBrowserLastDeclined);
return last_dismissed_value == 0;
}
void OnCheckIsDefaultBrowserFinished(
Profile* profile,
shell_integration::DefaultWebClientState state) {
if (state == shell_integration::IS_DEFAULT) {
// Notify the user in the future if Chrome ceases to be the user's chosen
// default browser.
DefaultBrowserPromptManager::ResetPromptPrefs(profile);
} else if (state == shell_integration::NOT_DEFAULT &&
shell_integration::CanSetAsDefaultBrowser() &&
ShouldShowDefaultBrowserPromptForCurrentVersion()) {
// If the user is in the control or an experiment arm, move them into the
// synthetic trial cohort.
DefaultBrowserPromptTrial::MaybeJoinDefaultBrowserPromptCohort();
DefaultBrowserPromptManager::MaybeResetAppMenuPromptPrefs(profile);
// Only show the prompt if some other program is the user's default browser.
// In particular, don't show it if another install mode is default (e.g.,
// don't prompt for Chrome Beta if stable Chrome is the default).
if (base::FeatureList::IsEnabled(features::kDefaultBrowserPromptRefresh)) {
DefaultBrowserPromptManager::GetInstance()->MaybeShowPrompt();
} else if (ShouldShowDefaultBrowserPrompt(profile)) {
ShowPrompt();
}
}
}
} // namespace
void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(
prefs::kBrowserSuppressDefaultBrowserPrompt, std::string());
registry->RegisterStringPref(prefs::kDefaultBrowserPromptRefreshStudyGroup,
std::string());
}
// Migrates the last declined time from the old int pref (profile) to the new
// Time pref (local). Does not clear the old pref as it is still needed to
// preserve the original behavior for the duration of the experiment.
// TODO(326079444): After experiment is over, change this function to also clear
// the old pref.
void MigrateDefaultBrowserLastDeclinedPref(PrefService* profile_prefs) {
PrefService* local_state = g_browser_process->local_state();
if (!local_state) {
CHECK_IS_TEST();
return;
}
const PrefService::Preference* old_last_declined_time_pref =
profile_prefs->FindPreference(prefs::kDefaultBrowserLastDeclined);
const PrefService::Preference* last_declined_time_pref =
local_state->FindPreference(prefs::kDefaultBrowserLastDeclinedTime);
if (old_last_declined_time_pref->IsDefaultValue()) {
return;
}
base::Time old_last_declined_time = base::Time::FromInternalValue(
profile_prefs->GetInt64(prefs::kDefaultBrowserLastDeclined));
base::Time last_declined_time =
local_state->GetTime(prefs::kDefaultBrowserLastDeclinedTime);
// Migrate if the local pref has never been set before, or if the local pref's
// value was migrated from a different profile and the current profile's pref
// has a value that is more recent. It is not possible to overwrite a user-set
// value for the local pref as both the new pref and the old pref are kept in
// sync from the moment the new pref is introduced.
if (last_declined_time_pref->IsDefaultValue() ||
old_last_declined_time > last_declined_time) {
local_state->SetTime(prefs::kDefaultBrowserLastDeclinedTime,
old_last_declined_time);
if (local_state->GetInteger(prefs::kDefaultBrowserDeclinedCount) == 0) {
local_state->SetInteger(prefs::kDefaultBrowserDeclinedCount, 1);
}
}
}
void ShowDefaultBrowserPrompt(Profile* profile) {
// Do not check if Chrome is the default browser if there is a policy in
// control of this setting.
if (g_browser_process->local_state()->IsManagedPreference(
prefs::kDefaultBrowserSettingEnabled)) {
// Handling of the browser.default_browser_setting_enabled policy setting is
// taken care of in BrowserProcessImpl.
return;
}
scoped_refptr<shell_integration::DefaultBrowserWorker>(
new shell_integration::DefaultBrowserWorker())
->StartCheckIsDefault(
base::BindOnce(&OnCheckIsDefaultBrowserFinished, profile));
}
void ShowPromptForTesting() {
ShowPrompt();
}