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 "base/memory/weak_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/version.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/first_run/first_run.h"
15 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
16 #include "chrome/browser/infobars/infobar.h"
17 #include "chrome/browser/infobars/infobar_service.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/shell_integration.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/common/chrome_version_info.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/installer/util/master_preferences.h"
26 #include "chrome/installer/util/master_preferences_constants.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/navigation_details.h"
29 #include "content/public/browser/web_contents.h"
30 #include "grit/chromium_strings.h"
31 #include "grit/generated_resources.h"
32 #include "grit/theme_resources.h"
33 #include "ui/base/l10n/l10n_util.h"
38 // Calls the appropriate function for setting Chrome as the default browser.
39 // This requires IO access (registry) and may result in interaction with a
41 void SetChromeAsDefaultBrowser(bool interactive_flow
, PrefService
* prefs
) {
42 if (interactive_flow
) {
43 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefaultUI", 1);
44 if (!ShellIntegration::SetAsDefaultBrowserInteractive()) {
45 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefaultUIFailed", 1);
46 } else if (ShellIntegration::GetDefaultBrowser() ==
47 ShellIntegration::NOT_DEFAULT
) {
48 // If the interaction succeeded but we are still not the default browser
49 // it likely means the user simply selected another browser from the
50 // panel. We will respect this choice and write it down as 'no, thanks'.
51 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1);
54 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1);
55 ShellIntegration::SetAsDefaultBrowser();
59 // The delegate for the infobar shown when Chrome is not the default browser.
60 class DefaultBrowserInfoBarDelegate
: public ConfirmInfoBarDelegate
{
62 // Creates a default browser infobar and delegate and adds the infobar to
64 static void Create(InfoBarService
* infobar_service
,
66 bool interactive_flow_required
);
69 DefaultBrowserInfoBarDelegate(PrefService
* prefs
,
70 bool interactive_flow_required
);
71 virtual ~DefaultBrowserInfoBarDelegate();
73 void AllowExpiry() { should_expire_
= true; }
75 // ConfirmInfoBarDelegate:
76 virtual int GetIconID() const OVERRIDE
;
77 virtual base::string16
GetMessageText() const OVERRIDE
;
78 virtual base::string16
GetButtonLabel(InfoBarButton button
) const OVERRIDE
;
79 virtual bool NeedElevation(InfoBarButton button
) const OVERRIDE
;
80 virtual bool Accept() OVERRIDE
;
81 virtual bool Cancel() OVERRIDE
;
82 virtual bool ShouldExpireInternal(
83 const content::LoadCommittedDetails
& details
) const OVERRIDE
;
88 // Whether the user clicked one of the buttons.
91 // Whether the info-bar should be dismissed on the next navigation.
94 // Whether changing the default application will require entering the
96 const bool interactive_flow_required_
;
98 // Used to delay the expiration of the info-bar.
99 base::WeakPtrFactory
<DefaultBrowserInfoBarDelegate
> weak_factory_
;
101 DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate
);
105 void DefaultBrowserInfoBarDelegate::Create(InfoBarService
* infobar_service
,
107 bool interactive_flow_required
) {
108 infobar_service
->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
109 scoped_ptr
<ConfirmInfoBarDelegate
>(new DefaultBrowserInfoBarDelegate(
110 prefs
, interactive_flow_required
))));
113 DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate(
115 bool interactive_flow_required
)
116 : ConfirmInfoBarDelegate(),
118 action_taken_(false),
119 should_expire_(false),
120 interactive_flow_required_(interactive_flow_required
),
121 weak_factory_(this) {
122 // We want the info-bar to stick-around for few seconds and then be hidden
123 // on the next navigation after that.
124 base::MessageLoop::current()->PostDelayedTask(
126 base::Bind(&DefaultBrowserInfoBarDelegate::AllowExpiry
,
127 weak_factory_
.GetWeakPtr()),
128 base::TimeDelta::FromSeconds(8));
131 DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() {
133 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1);
136 int DefaultBrowserInfoBarDelegate::GetIconID() const {
137 return IDR_PRODUCT_LOGO_32
;
140 base::string16
DefaultBrowserInfoBarDelegate::GetMessageText() const {
141 return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT
);
144 base::string16
DefaultBrowserInfoBarDelegate::GetButtonLabel(
145 InfoBarButton button
) const {
146 return l10n_util::GetStringUTF16((button
== BUTTON_OK
) ?
147 IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL
:
148 IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL
);
151 bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button
) const {
152 return button
== BUTTON_OK
;
155 bool DefaultBrowserInfoBarDelegate::Accept() {
156 action_taken_
= true;
157 content::BrowserThread::PostTask(
158 content::BrowserThread::FILE, FROM_HERE
,
159 base::Bind(&SetChromeAsDefaultBrowser
, interactive_flow_required_
,
165 bool DefaultBrowserInfoBarDelegate::Cancel() {
166 action_taken_
= true;
167 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1);
168 // User clicked "Don't ask me again", remember that.
169 prefs_
->SetBoolean(prefs::kCheckDefaultBrowser
, false);
173 bool DefaultBrowserInfoBarDelegate::ShouldExpireInternal(
174 const content::LoadCommittedDetails
& details
) const {
175 return should_expire_
;
178 void NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type
) {
179 Browser
* browser
= chrome::FindLastActiveWithHostDesktopType(desktop_type
);
181 return; // Reached during ui tests.
183 // In ChromeBot tests, there might be a race. This line appears to get
184 // called during shutdown and |tab| can be NULL.
185 content::WebContents
* web_contents
=
186 browser
->tab_strip_model()->GetActiveWebContents();
190 DefaultBrowserInfoBarDelegate::Create(
191 InfoBarService::FromWebContents(web_contents
),
192 Profile::FromBrowserContext(
193 web_contents
->GetBrowserContext())->GetPrefs(),
194 (ShellIntegration::CanSetAsDefaultBrowser() ==
195 ShellIntegration::SET_DEFAULT_INTERACTIVE
));
198 void CheckDefaultBrowserCallback(chrome::HostDesktopType desktop_type
) {
199 if (ShellIntegration::GetDefaultBrowser() == ShellIntegration::NOT_DEFAULT
) {
200 ShellIntegration::DefaultWebClientSetPermission default_change_mode
=
201 ShellIntegration::CanSetAsDefaultBrowser();
203 if (default_change_mode
!= ShellIntegration::SET_DEFAULT_NOT_ALLOWED
) {
204 content::BrowserThread::PostTask(
205 content::BrowserThread::UI
, FROM_HERE
,
206 base::Bind(&NotifyNotDefaultBrowserCallback
, desktop_type
));
215 void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple
* registry
) {
216 registry
->RegisterStringPref(
217 prefs::kBrowserSuppressDefaultBrowserPrompt
, std::string());
220 void ShowDefaultBrowserPrompt(Profile
* profile
, HostDesktopType desktop_type
) {
221 // We do not check if we are the default browser if:
222 // - The user said "don't ask me again" on the infobar earlier.
223 // - There is a policy in control of this setting.
224 // - The "suppress_default_browser_prompt_for_version" master preference is
225 // set to the current version.
226 if (!profile
->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser
))
229 if (g_browser_process
->local_state()->IsManagedPreference(
230 prefs::kDefaultBrowserSettingEnabled
)) {
231 if (g_browser_process
->local_state()->GetBoolean(
232 prefs::kDefaultBrowserSettingEnabled
)) {
233 content::BrowserThread::PostTask(
234 content::BrowserThread::FILE, FROM_HERE
,
236 base::IgnoreResult(&ShellIntegration::SetAsDefaultBrowser
)));
238 // TODO(pastarmovj): We can't really do anything meaningful here yet but
239 // just prevent showing the infobar.
244 const std::string disable_version_string
=
245 g_browser_process
->local_state()->GetString(
246 prefs::kBrowserSuppressDefaultBrowserPrompt
);
247 const Version
disable_version(disable_version_string
);
248 DCHECK(disable_version_string
.empty() || disable_version
.IsValid());
249 if (disable_version
.IsValid()) {
250 const chrome::VersionInfo version_info
;
251 if (disable_version
.Equals(Version(version_info
.Version())))
255 content::BrowserThread::PostTask(
256 content::BrowserThread::FILE, FROM_HERE
,
257 base::Bind(&CheckDefaultBrowserCallback
, desktop_type
));
262 bool ShowFirstRunDefaultBrowserPrompt(Profile
* profile
) {
267 } // namespace chrome