default_browser_prompt.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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.h"
9#include "base/metrics/histogram.h"
10#include "chrome/browser/api/infobars/confirm_infobar_delegate.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/first_run/first_run.h"
13#include "chrome/browser/infobars/infobar_tab_helper.h"
14#include "chrome/browser/prefs/pref_service.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/shell_integration.h"
17#include "chrome/browser/ui/browser.h"
18#include "chrome/browser/ui/browser_finder.h"
19#include "chrome/browser/ui/browser_tabstrip.h"
20#include "chrome/common/pref_names.h"
21#include "content/public/browser/browser_thread.h"
22#include "content/public/browser/navigation_details.h"
23#include "grit/chromium_strings.h"
24#include "grit/generated_resources.h"
25#include "grit/theme_resources.h"
26#include "ui/base/l10n/l10n_util.h"
27#include "ui/base/resource/resource_bundle.h"
28
29using content::BrowserThread;
30
31namespace {
32
33// Calls the appropriate function for setting Chrome as the default browser.
34// This requires IO access (registry) and may result in interaction with a
35// modal system UI.
36void SetChromeAsDefaultBrowser(bool interactive_flow, PrefService* prefs) {
37  if (interactive_flow) {
38    UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefaultUI", 1);
39    if (!ShellIntegration::SetAsDefaultBrowserInteractive()) {
40      UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefaultUIFailed", 1);
41    } else if (!ShellIntegration::IsDefaultBrowser()) {
42      // If the interaction succeeded but we are still not the default browser
43      // it likely means the user simply selected another browser from the
44      // panel. We will respect this choice and write it down as 'no, thanks'.
45      UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1);
46    }
47  } else {
48    UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1);
49    ShellIntegration::SetAsDefaultBrowser();
50  }
51}
52
53// The delegate for the infobar shown when Chrome is not the default browser.
54class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
55 public:
56  DefaultBrowserInfoBarDelegate(InfoBarTabHelper* infobar_helper,
57                                PrefService* prefs,
58                                bool interactive_flow_required);
59
60 private:
61  virtual ~DefaultBrowserInfoBarDelegate();
62
63  void AllowExpiry() { should_expire_ = true; }
64
65  // ConfirmInfoBarDelegate:
66  virtual gfx::Image* GetIcon() const OVERRIDE;
67  virtual string16 GetMessageText() const OVERRIDE;
68  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
69  virtual bool NeedElevation(InfoBarButton button) const OVERRIDE;
70  virtual bool Accept() OVERRIDE;
71  virtual bool Cancel() OVERRIDE;
72  virtual bool ShouldExpireInternal(
73      const content::LoadCommittedDetails& details) const OVERRIDE;
74
75  // The prefs to use.
76  PrefService* prefs_;
77
78  // Whether the user clicked one of the buttons.
79  bool action_taken_;
80
81  // Whether the info-bar should be dismissed on the next navigation.
82  bool should_expire_;
83
84  // Whether changing the default application will require entering the
85  // modal-UI flow.
86  const bool interactive_flow_required_;
87
88  // Used to delay the expiration of the info-bar.
89  base::WeakPtrFactory<DefaultBrowserInfoBarDelegate> weak_factory_;
90
91  DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate);
92};
93
94DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate(
95    InfoBarTabHelper* infobar_helper,
96    PrefService* prefs,
97    bool interactive_flow_required)
98    : ConfirmInfoBarDelegate(infobar_helper),
99      prefs_(prefs),
100      action_taken_(false),
101      should_expire_(false),
102      interactive_flow_required_(interactive_flow_required),
103      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
104  // We want the info-bar to stick-around for few seconds and then be hidden
105  // on the next navigation after that.
106  MessageLoop::current()->PostDelayedTask(
107      FROM_HERE, base::Bind(&DefaultBrowserInfoBarDelegate::AllowExpiry,
108                            weak_factory_.GetWeakPtr()),
109      base::TimeDelta::FromSeconds(8));
110}
111
112DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() {
113  if (!action_taken_)
114    UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1);
115}
116
117gfx::Image* DefaultBrowserInfoBarDelegate::GetIcon() const {
118  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
119     IDR_PRODUCT_LOGO_32);
120}
121
122string16 DefaultBrowserInfoBarDelegate::GetMessageText() const {
123  return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
124}
125
126string16 DefaultBrowserInfoBarDelegate::GetButtonLabel(
127    InfoBarButton button) const {
128  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
129      IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL :
130      IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL);
131}
132
133bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button) const {
134  return button == BUTTON_OK;
135}
136
137bool DefaultBrowserInfoBarDelegate::Accept() {
138  action_taken_ = true;
139  BrowserThread::PostTask(
140      BrowserThread::FILE,
141      FROM_HERE,
142      base::Bind(&SetChromeAsDefaultBrowser, interactive_flow_required_,
143                 prefs_));
144
145  return true;
146}
147
148bool DefaultBrowserInfoBarDelegate::Cancel() {
149  action_taken_ = true;
150  UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1);
151  // User clicked "Don't ask me again", remember that.
152  prefs_->SetBoolean(prefs::kCheckDefaultBrowser, false);
153  return true;
154}
155
156bool DefaultBrowserInfoBarDelegate::ShouldExpireInternal(
157    const content::LoadCommittedDetails& details) const {
158  return should_expire_;
159}
160
161void NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type) {
162  Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
163  if (!browser)
164    return;  // Reached during ui tests.
165
166  // In ChromeBot tests, there might be a race. This line appears to get
167  // called during shutdown and |tab| can be NULL.
168  content::WebContents* web_contents = chrome::GetActiveWebContents(browser);
169  if (!web_contents)
170    return;
171
172  // Don't show the info-bar if there are already info-bars showing.
173  InfoBarTabHelper* infobar_helper =
174      InfoBarTabHelper::FromWebContents(web_contents);
175  if (infobar_helper->GetInfoBarCount() > 0)
176    return;
177
178  bool interactive_flow = ShellIntegration::CanSetAsDefaultBrowser() ==
179      ShellIntegration::SET_DEFAULT_INTERACTIVE;
180  Profile* profile =
181      Profile::FromBrowserContext(web_contents->GetBrowserContext());
182  infobar_helper->AddInfoBar(
183      new DefaultBrowserInfoBarDelegate(infobar_helper,
184                                        profile->GetPrefs(),
185                                        interactive_flow));
186}
187
188void CheckDefaultBrowserCallback(chrome::HostDesktopType desktop_type) {
189  if (!ShellIntegration::IsDefaultBrowser()) {
190    ShellIntegration::DefaultWebClientSetPermission default_change_mode =
191        ShellIntegration::CanSetAsDefaultBrowser();
192
193    if (default_change_mode != ShellIntegration::SET_DEFAULT_NOT_ALLOWED) {
194      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
195          base::Bind(&NotifyNotDefaultBrowserCallback, desktop_type));
196    }
197  }
198}
199
200}  // namespace
201
202namespace chrome {
203
204void ShowDefaultBrowserPrompt(Profile* profile, HostDesktopType desktop_type) {
205  // We do not check if we are the default browser if:
206  // - the user said "don't ask me again" on the infobar earlier.
207  // - There is a policy in control of this setting.
208  if (!profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser))
209    return;
210
211  if (g_browser_process->local_state()->IsManagedPreference(
212      prefs::kDefaultBrowserSettingEnabled)) {
213    if (g_browser_process->local_state()->GetBoolean(
214        prefs::kDefaultBrowserSettingEnabled)) {
215      BrowserThread::PostTask(
216          BrowserThread::FILE, FROM_HERE,
217          base::Bind(
218              base::IgnoreResult(&ShellIntegration::SetAsDefaultBrowser)));
219    } else {
220      // TODO(pastarmovj): We can't really do anything meaningful here yet but
221      // just prevent showing the infobar.
222    }
223    return;
224  }
225  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
226                          base::Bind(&CheckDefaultBrowserCallback,
227                                     desktop_type));
228
229}
230
231#if !defined(OS_WIN)
232bool ShowFirstRunDefaultBrowserPrompt(Profile* profile) {
233  return false;
234}
235#endif
236
237}  // namespace chrome
238