default_browser_prompt.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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/confirm_infobar_delegate.h" 16#include "chrome/browser/infobars/infobar_service.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/browser/shell_integration.h" 19#include "chrome/browser/ui/browser.h" 20#include "chrome/browser/ui/browser_finder.h" 21#include "chrome/browser/ui/tabs/tab_strip_model.h" 22#include "chrome/common/chrome_version_info.h" 23#include "chrome/common/pref_names.h" 24#include "chrome/installer/util/master_preferences.h" 25#include "chrome/installer/util/master_preferences_constants.h" 26#include "content/public/browser/browser_thread.h" 27#include "content/public/browser/navigation_details.h" 28#include "content/public/browser/web_contents.h" 29#include "grit/chromium_strings.h" 30#include "grit/generated_resources.h" 31#include "grit/theme_resources.h" 32#include "ui/base/l10n/l10n_util.h" 33 34 35namespace { 36 37// Calls the appropriate function for setting Chrome as the default browser. 38// This requires IO access (registry) and may result in interaction with a 39// modal system UI. 40void SetChromeAsDefaultBrowser(bool interactive_flow, PrefService* prefs) { 41 if (interactive_flow) { 42 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefaultUI", 1); 43 if (!ShellIntegration::SetAsDefaultBrowserInteractive()) { 44 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefaultUIFailed", 1); 45 } else if (ShellIntegration::GetDefaultBrowser() == 46 ShellIntegration::NOT_DEFAULT) { 47 // If the interaction succeeded but we are still not the default browser 48 // it likely means the user simply selected another browser from the 49 // panel. We will respect this choice and write it down as 'no, thanks'. 50 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1); 51 } 52 } else { 53 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1); 54 ShellIntegration::SetAsDefaultBrowser(); 55 } 56} 57 58// The delegate for the infobar shown when Chrome is not the default browser. 59class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate { 60 public: 61 // Creates a default browser infobar delegate and adds it to 62 // |infobar_service|. 63 static void Create(InfoBarService* infobar_service, 64 PrefService* prefs, 65 bool interactive_flow_required); 66 67 private: 68 DefaultBrowserInfoBarDelegate(InfoBarService* infobar_service, 69 PrefService* prefs, 70 bool interactive_flow_required); 71 virtual ~DefaultBrowserInfoBarDelegate(); 72 73 void AllowExpiry() { should_expire_ = true; } 74 75 // ConfirmInfoBarDelegate: 76 virtual int GetIconID() const OVERRIDE; 77 virtual string16 GetMessageText() const OVERRIDE; 78 virtual 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; 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 105void DefaultBrowserInfoBarDelegate::Create(InfoBarService* infobar_service, 106 PrefService* prefs, 107 bool interactive_flow_required) { 108 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 109 new DefaultBrowserInfoBarDelegate(infobar_service, prefs, 110 interactive_flow_required))); 111} 112 113DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate( 114 InfoBarService* infobar_service, 115 PrefService* prefs, 116 bool interactive_flow_required) 117 : ConfirmInfoBarDelegate(infobar_service), 118 prefs_(prefs), 119 action_taken_(false), 120 should_expire_(false), 121 interactive_flow_required_(interactive_flow_required), 122 weak_factory_(this) { 123 // We want the info-bar to stick-around for few seconds and then be hidden 124 // on the next navigation after that. 125 base::MessageLoop::current()->PostDelayedTask( 126 FROM_HERE, 127 base::Bind(&DefaultBrowserInfoBarDelegate::AllowExpiry, 128 weak_factory_.GetWeakPtr()), 129 base::TimeDelta::FromSeconds(8)); 130} 131 132DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() { 133 if (!action_taken_) 134 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1); 135} 136 137int DefaultBrowserInfoBarDelegate::GetIconID() const { 138 return IDR_PRODUCT_LOGO_32; 139} 140 141string16 DefaultBrowserInfoBarDelegate::GetMessageText() const { 142 return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT); 143} 144 145string16 DefaultBrowserInfoBarDelegate::GetButtonLabel( 146 InfoBarButton button) const { 147 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 148 IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL : 149 IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL); 150} 151 152bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button) const { 153 return button == BUTTON_OK; 154} 155 156bool DefaultBrowserInfoBarDelegate::Accept() { 157 action_taken_ = true; 158 content::BrowserThread::PostTask( 159 content::BrowserThread::FILE, FROM_HERE, 160 base::Bind(&SetChromeAsDefaultBrowser, interactive_flow_required_, 161 prefs_)); 162 163 return true; 164} 165 166bool DefaultBrowserInfoBarDelegate::Cancel() { 167 action_taken_ = true; 168 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1); 169 // User clicked "Don't ask me again", remember that. 170 prefs_->SetBoolean(prefs::kCheckDefaultBrowser, false); 171 return true; 172} 173 174bool DefaultBrowserInfoBarDelegate::ShouldExpireInternal( 175 const content::LoadCommittedDetails& details) const { 176 return should_expire_; 177} 178 179void NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type) { 180 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type); 181 if (!browser) 182 return; // Reached during ui tests. 183 184 // In ChromeBot tests, there might be a race. This line appears to get 185 // called during shutdown and |tab| can be NULL. 186 content::WebContents* web_contents = 187 browser->tab_strip_model()->GetActiveWebContents(); 188 if (!web_contents) 189 return; 190 191 DefaultBrowserInfoBarDelegate::Create( 192 InfoBarService::FromWebContents(web_contents), 193 Profile::FromBrowserContext( 194 web_contents->GetBrowserContext())->GetPrefs(), 195 (ShellIntegration::CanSetAsDefaultBrowser() == 196 ShellIntegration::SET_DEFAULT_INTERACTIVE)); 197} 198 199void CheckDefaultBrowserCallback(chrome::HostDesktopType desktop_type) { 200 if (ShellIntegration::GetDefaultBrowser() == ShellIntegration::NOT_DEFAULT) { 201 ShellIntegration::DefaultWebClientSetPermission default_change_mode = 202 ShellIntegration::CanSetAsDefaultBrowser(); 203 204 if (default_change_mode != ShellIntegration::SET_DEFAULT_NOT_ALLOWED) { 205 content::BrowserThread::PostTask( 206 content::BrowserThread::UI, FROM_HERE, 207 base::Bind(&NotifyNotDefaultBrowserCallback, desktop_type)); 208 } 209 } 210} 211 212} // namespace 213 214namespace chrome { 215 216void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple* registry) { 217 registry->RegisterStringPref( 218 prefs::kBrowserSuppressDefaultBrowserPrompt, std::string()); 219} 220 221void ShowDefaultBrowserPrompt(Profile* profile, HostDesktopType desktop_type) { 222 // We do not check if we are the default browser if: 223 // - The user said "don't ask me again" on the infobar earlier. 224 // - There is a policy in control of this setting. 225 // - The "suppress_default_browser_prompt_for_version" master preference is 226 // set to the current version. 227 if (!profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser)) 228 return; 229 230 if (g_browser_process->local_state()->IsManagedPreference( 231 prefs::kDefaultBrowserSettingEnabled)) { 232 if (g_browser_process->local_state()->GetBoolean( 233 prefs::kDefaultBrowserSettingEnabled)) { 234 content::BrowserThread::PostTask( 235 content::BrowserThread::FILE, FROM_HERE, 236 base::Bind( 237 base::IgnoreResult(&ShellIntegration::SetAsDefaultBrowser))); 238 } else { 239 // TODO(pastarmovj): We can't really do anything meaningful here yet but 240 // just prevent showing the infobar. 241 } 242 return; 243 } 244 245 const std::string disable_version_string = 246 g_browser_process->local_state()->GetString( 247 prefs::kBrowserSuppressDefaultBrowserPrompt); 248 const Version disable_version(disable_version_string); 249 DCHECK(disable_version_string.empty() || disable_version.IsValid()); 250 if (disable_version.IsValid()) { 251 const chrome::VersionInfo version_info; 252 if (disable_version.Equals(Version(version_info.Version()))) 253 return; 254 } 255 256 content::BrowserThread::PostTask( 257 content::BrowserThread::FILE, FROM_HERE, 258 base::Bind(&CheckDefaultBrowserCallback, desktop_type)); 259 260} 261 262#if !defined(OS_WIN) 263bool ShowFirstRunDefaultBrowserPrompt(Profile* profile) { 264 return false; 265} 266#endif 267 268} // namespace chrome 269