• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/ui/startup/default_browser_prompt.h"
6 
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/infobar_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/shell_integration.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/common/chrome_version_info.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/grit/chromium_strings.h"
24 #include "chrome/grit/generated_resources.h"
25 #include "chrome/installer/util/master_preferences.h"
26 #include "chrome/installer/util/master_preferences_constants.h"
27 #include "components/infobars/core/confirm_infobar_delegate.h"
28 #include "components/infobars/core/infobar.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/navigation_details.h"
31 #include "content/public/browser/web_contents.h"
32 #include "grit/theme_resources.h"
33 #include "ui/base/l10n/l10n_util.h"
34 
35 
36 namespace {
37 
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
40 // modal system UI.
SetChromeAsDefaultBrowser(bool interactive_flow,PrefService * prefs)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);
52     }
53   } else {
54     UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1);
55     ShellIntegration::SetAsDefaultBrowser();
56   }
57 }
58 
59 // The delegate for the infobar shown when Chrome is not the default browser.
60 class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
61  public:
62   // Creates a default browser infobar and delegate and adds the infobar to
63   // |infobar_service|.
64   static void Create(InfoBarService* infobar_service,
65                      PrefService* prefs,
66                      bool interactive_flow_required);
67 
68  private:
69   DefaultBrowserInfoBarDelegate(PrefService* prefs,
70                                 bool interactive_flow_required);
71   virtual ~DefaultBrowserInfoBarDelegate();
72 
AllowExpiry()73   void AllowExpiry() { should_expire_ = true; }
74 
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 OKButtonTriggersUACPrompt() const OVERRIDE;
80   virtual bool Accept() OVERRIDE;
81   virtual bool Cancel() OVERRIDE;
82   virtual bool ShouldExpireInternal(
83       const NavigationDetails& details) const OVERRIDE;
84 
85   // The prefs to use.
86   PrefService* prefs_;
87 
88   // Whether the user clicked one of the buttons.
89   bool action_taken_;
90 
91   // Whether the info-bar should be dismissed on the next navigation.
92   bool should_expire_;
93 
94   // Whether changing the default application will require entering the
95   // modal-UI flow.
96   const bool interactive_flow_required_;
97 
98   // Used to delay the expiration of the info-bar.
99   base::WeakPtrFactory<DefaultBrowserInfoBarDelegate> weak_factory_;
100 
101   DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate);
102 };
103 
104 // static
Create(InfoBarService * infobar_service,PrefService * prefs,bool interactive_flow_required)105 void DefaultBrowserInfoBarDelegate::Create(InfoBarService* infobar_service,
106                                            PrefService* prefs,
107                                            bool interactive_flow_required) {
108   infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
109       scoped_ptr<ConfirmInfoBarDelegate>(new DefaultBrowserInfoBarDelegate(
110           prefs, interactive_flow_required))));
111 }
112 
DefaultBrowserInfoBarDelegate(PrefService * prefs,bool interactive_flow_required)113 DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate(
114     PrefService* prefs,
115     bool interactive_flow_required)
116     : ConfirmInfoBarDelegate(),
117       prefs_(prefs),
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(
125       FROM_HERE,
126       base::Bind(&DefaultBrowserInfoBarDelegate::AllowExpiry,
127                  weak_factory_.GetWeakPtr()),
128       base::TimeDelta::FromSeconds(8));
129 }
130 
~DefaultBrowserInfoBarDelegate()131 DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() {
132   if (!action_taken_)
133     UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1);
134 }
135 
GetIconID() const136 int DefaultBrowserInfoBarDelegate::GetIconID() const {
137   return IDR_PRODUCT_LOGO_32;
138 }
139 
GetMessageText() const140 base::string16 DefaultBrowserInfoBarDelegate::GetMessageText() const {
141   return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
142 }
143 
GetButtonLabel(InfoBarButton button) const144 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);
149 }
150 
OKButtonTriggersUACPrompt() const151 bool DefaultBrowserInfoBarDelegate::OKButtonTriggersUACPrompt() const {
152   return true;
153 }
154 
Accept()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_,
160                  prefs_));
161 
162   return true;
163 }
164 
Cancel()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);
170   return true;
171 }
172 
ShouldExpireInternal(const NavigationDetails & details) const173 bool DefaultBrowserInfoBarDelegate::ShouldExpireInternal(
174     const NavigationDetails& details) const {
175   return should_expire_;
176 }
177 
NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type)178 void NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type) {
179   Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
180   if (!browser)
181     return;  // Reached during ui tests.
182 
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();
187   if (!web_contents)
188     return;
189 
190   DefaultBrowserInfoBarDelegate::Create(
191       InfoBarService::FromWebContents(web_contents),
192       Profile::FromBrowserContext(
193           web_contents->GetBrowserContext())->GetPrefs(),
194       (ShellIntegration::CanSetAsDefaultBrowser() ==
195           ShellIntegration::SET_DEFAULT_INTERACTIVE));
196 }
197 
CheckDefaultBrowserCallback(chrome::HostDesktopType desktop_type)198 void CheckDefaultBrowserCallback(chrome::HostDesktopType desktop_type) {
199   if (ShellIntegration::GetDefaultBrowser() == ShellIntegration::NOT_DEFAULT) {
200     ShellIntegration::DefaultWebClientSetPermission default_change_mode =
201         ShellIntegration::CanSetAsDefaultBrowser();
202 
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));
207     }
208   }
209 }
210 
211 }  // namespace
212 
213 namespace chrome {
214 
RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple * registry)215 void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple* registry) {
216   registry->RegisterStringPref(
217       prefs::kBrowserSuppressDefaultBrowserPrompt, std::string());
218 }
219 
ShowDefaultBrowserPrompt(Profile * profile,HostDesktopType desktop_type)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))
227     return;
228 
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,
235           base::Bind(
236               base::IgnoreResult(&ShellIntegration::SetAsDefaultBrowser)));
237     } else {
238       // TODO(pastarmovj): We can't really do anything meaningful here yet but
239       // just prevent showing the infobar.
240     }
241     return;
242   }
243 
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())))
252       return;
253   }
254 
255   content::BrowserThread::PostTask(
256       content::BrowserThread::FILE, FROM_HERE,
257       base::Bind(&CheckDefaultBrowserCallback, desktop_type));
258 }
259 
260 #if !defined(OS_WIN)
ShowFirstRunDefaultBrowserPrompt(Profile * profile)261 bool ShowFirstRunDefaultBrowserPrompt(Profile* profile) {
262   return false;
263 }
264 #endif
265 
266 }  // namespace chrome
267