Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / startup / default_browser_prompt.cc
blob353c3c7bf6297306cd1dceb3d863ad00f86b0e93
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/startup/default_browser_prompt.h"
7 #include <string>
9 #include "base/location.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/version.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/first_run/first_run.h"
19 #include "chrome/browser/infobars/infobar_service.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/browser/shell_integration.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_finder.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/grit/chromium_strings.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "chrome/installer/util/master_preferences.h"
30 #include "chrome/installer/util/master_preferences_constants.h"
31 #include "components/infobars/core/confirm_infobar_delegate.h"
32 #include "components/infobars/core/infobar.h"
33 #include "components/version_info/version_info.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/navigation_details.h"
36 #include "content/public/browser/web_contents.h"
37 #include "grit/theme_resources.h"
38 #include "ui/base/l10n/l10n_util.h"
41 namespace {
43 // Calls the appropriate function for setting Chrome as the default browser.
44 // This requires IO access (registry) and may result in interaction with a
45 // modal system UI.
46 void SetChromeAsDefaultBrowser(bool interactive_flow, PrefService* prefs) {
47 if (interactive_flow) {
48 UMA_HISTOGRAM_BOOLEAN("DefaultBrowserWarning.SetAsDefaultUI", true);
49 if (!ShellIntegration::SetAsDefaultBrowserInteractive()) {
50 UMA_HISTOGRAM_BOOLEAN("DefaultBrowserWarning.SetAsDefaultUIFailed", true);
51 } else if (ShellIntegration::GetDefaultBrowser() ==
52 ShellIntegration::NOT_DEFAULT) {
53 // If the interaction succeeded but we are still not the default browser
54 // it likely means the user simply selected another browser from the
55 // panel. We will respect this choice and write it down as 'no, thanks'.
56 UMA_HISTOGRAM_BOOLEAN("DefaultBrowserWarning.DontSetAsDefault", true);
58 } else {
59 UMA_HISTOGRAM_BOOLEAN("DefaultBrowserWarning.SetAsDefault", true);
60 ShellIntegration::SetAsDefaultBrowser();
64 // The delegate for the infobar shown when Chrome is not the default browser.
65 class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
66 public:
67 // Creates a default browser infobar and delegate and adds the infobar to
68 // |infobar_service|.
69 static void Create(InfoBarService* infobar_service,
70 PrefService* prefs,
71 bool interactive_flow_required);
73 private:
74 DefaultBrowserInfoBarDelegate(PrefService* prefs,
75 bool interactive_flow_required);
76 ~DefaultBrowserInfoBarDelegate() override;
78 void AllowExpiry() { should_expire_ = true; }
80 // ConfirmInfoBarDelegate:
81 int GetIconId() const override;
82 bool ShouldExpire(const NavigationDetails& details) const override;
83 base::string16 GetMessageText() const override;
84 base::string16 GetButtonLabel(InfoBarButton button) const override;
85 bool OKButtonTriggersUACPrompt() const override;
86 bool Accept() override;
87 bool Cancel() override;
89 // The prefs to use.
90 PrefService* prefs_;
92 // Whether the user clicked one of the buttons.
93 bool action_taken_;
95 // Whether the info-bar should be dismissed on the next navigation.
96 bool should_expire_;
98 // Whether changing the default application will require entering the
99 // modal-UI flow.
100 const bool interactive_flow_required_;
102 // Used to delay the expiration of the info-bar.
103 base::WeakPtrFactory<DefaultBrowserInfoBarDelegate> weak_factory_;
105 DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate);
108 // static
109 void DefaultBrowserInfoBarDelegate::Create(InfoBarService* infobar_service,
110 PrefService* prefs,
111 bool interactive_flow_required) {
112 infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
113 scoped_ptr<ConfirmInfoBarDelegate>(new DefaultBrowserInfoBarDelegate(
114 prefs, interactive_flow_required))));
117 DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate(
118 PrefService* prefs,
119 bool interactive_flow_required)
120 : ConfirmInfoBarDelegate(),
121 prefs_(prefs),
122 action_taken_(false),
123 should_expire_(false),
124 interactive_flow_required_(interactive_flow_required),
125 weak_factory_(this) {
126 // We want the info-bar to stick-around for few seconds and then be hidden
127 // on the next navigation after that.
128 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
129 FROM_HERE, base::Bind(&DefaultBrowserInfoBarDelegate::AllowExpiry,
130 weak_factory_.GetWeakPtr()),
131 base::TimeDelta::FromSeconds(8));
134 DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() {
135 if (!action_taken_)
136 UMA_HISTOGRAM_BOOLEAN("DefaultBrowserWarning.Ignored", true);
139 int DefaultBrowserInfoBarDelegate::GetIconId() const {
140 return IDR_PRODUCT_LOGO_32;
143 bool DefaultBrowserInfoBarDelegate::ShouldExpire(
144 const NavigationDetails& details) const {
145 return should_expire_ && ConfirmInfoBarDelegate::ShouldExpire(details);
148 base::string16 DefaultBrowserInfoBarDelegate::GetMessageText() const {
149 return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
152 base::string16 DefaultBrowserInfoBarDelegate::GetButtonLabel(
153 InfoBarButton button) const {
154 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
155 IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL :
156 IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL);
159 // Setting an app as the default browser doesn't require elevation directly, but
160 // it does require registering it as the protocol handler for "http", so if
161 // protocol registration in general requires elevation, this does as well.
162 bool DefaultBrowserInfoBarDelegate::OKButtonTriggersUACPrompt() const {
163 return ShellIntegration::IsElevationNeededForSettingDefaultProtocolClient();
166 bool DefaultBrowserInfoBarDelegate::Accept() {
167 action_taken_ = true;
168 content::BrowserThread::PostTask(
169 content::BrowserThread::FILE, FROM_HERE,
170 base::Bind(&SetChromeAsDefaultBrowser, interactive_flow_required_,
171 prefs_));
173 return true;
176 bool DefaultBrowserInfoBarDelegate::Cancel() {
177 action_taken_ = true;
178 UMA_HISTOGRAM_BOOLEAN("DefaultBrowserWarning.DontSetAsDefault", true);
179 // User clicked "Don't ask me again", remember that.
180 prefs_->SetBoolean(prefs::kCheckDefaultBrowser, false);
181 return true;
184 void NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type) {
185 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
186 if (!browser)
187 return; // Reached during ui tests.
189 // In ChromeBot tests, there might be a race. This line appears to get
190 // called during shutdown and |tab| can be NULL.
191 content::WebContents* web_contents =
192 browser->tab_strip_model()->GetActiveWebContents();
193 if (!web_contents)
194 return;
196 DefaultBrowserInfoBarDelegate::Create(
197 InfoBarService::FromWebContents(web_contents),
198 Profile::FromBrowserContext(
199 web_contents->GetBrowserContext())->GetPrefs(),
200 (ShellIntegration::CanSetAsDefaultBrowser() ==
201 ShellIntegration::SET_DEFAULT_INTERACTIVE));
204 void ResetCheckDefaultBrowserPrefOnUIThread(
205 const base::FilePath& profile_path) {
206 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
207 Profile* profile =
208 g_browser_process->profile_manager()->GetProfileByPath(profile_path);
209 if (profile)
210 profile->GetPrefs()->SetBoolean(prefs::kCheckDefaultBrowser, true);
213 void CheckDefaultBrowserOnFileThread(const base::FilePath& profile_path,
214 bool show_prompt,
215 chrome::HostDesktopType desktop_type) {
216 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
217 ShellIntegration::DefaultWebClientState state =
218 ShellIntegration::GetDefaultBrowser();
219 if (state == ShellIntegration::IS_DEFAULT) {
220 // Notify the user in the future if Chrome ceases to be the user's chosen
221 // default browser.
222 content::BrowserThread::PostTask(
223 content::BrowserThread::UI, FROM_HERE,
224 base::Bind(&ResetCheckDefaultBrowserPrefOnUIThread, profile_path));
225 } else if (show_prompt && state == ShellIntegration::NOT_DEFAULT) {
226 ShellIntegration::DefaultWebClientSetPermission default_change_mode =
227 ShellIntegration::CanSetAsDefaultBrowser();
229 if (default_change_mode != ShellIntegration::SET_DEFAULT_NOT_ALLOWED) {
230 content::BrowserThread::PostTask(
231 content::BrowserThread::UI, FROM_HERE,
232 base::Bind(&NotifyNotDefaultBrowserCallback, desktop_type));
237 } // namespace
239 namespace chrome {
241 void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple* registry) {
242 registry->RegisterStringPref(
243 prefs::kBrowserSuppressDefaultBrowserPrompt, std::string());
246 void ShowDefaultBrowserPrompt(Profile* profile, HostDesktopType desktop_type) {
247 // We do not check if we are the default browser if:
248 // - There is a policy in control of this setting.
249 // We check if we are the default browser but do not prompt if:
250 // - The user said "don't ask me again" on the infobar earlier.
251 // - The "suppress_default_browser_prompt_for_version" master preference is
252 // set to the current version.
253 bool show_prompt =
254 profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser);
256 if (g_browser_process->local_state()->IsManagedPreference(
257 prefs::kDefaultBrowserSettingEnabled)) {
258 if (g_browser_process->local_state()->GetBoolean(
259 prefs::kDefaultBrowserSettingEnabled)) {
260 content::BrowserThread::PostTask(
261 content::BrowserThread::FILE, FROM_HERE,
262 base::Bind(
263 base::IgnoreResult(&ShellIntegration::SetAsDefaultBrowser)));
264 } else {
265 // TODO(pastarmovj): We can't really do anything meaningful here yet but
266 // just prevent showing the infobar.
268 return;
271 if (show_prompt) {
272 const std::string disable_version_string =
273 g_browser_process->local_state()->GetString(
274 prefs::kBrowserSuppressDefaultBrowserPrompt);
275 const Version disable_version(disable_version_string);
276 DCHECK(disable_version_string.empty() || disable_version.IsValid());
277 if (disable_version.IsValid()) {
278 if (disable_version.Equals(Version(version_info::GetVersionNumber())))
279 show_prompt = false;
283 content::BrowserThread::PostTask(
284 content::BrowserThread::FILE, FROM_HERE,
285 base::Bind(&CheckDefaultBrowserOnFileThread, profile->GetPath(),
286 show_prompt, desktop_type));
289 #if !defined(OS_WIN)
290 bool ShowFirstRunDefaultBrowserPrompt(Profile* profile) {
291 return false;
293 #endif
295 } // namespace chrome