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