default_browser_prompt.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/installer/util/master_preferences.h" 24#include "chrome/installer/util/master_preferences_constants.h" 25#include "components/infobars/core/confirm_infobar_delegate.h" 26#include "components/infobars/core/infobar.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" 34 35 36namespace { 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. 41void 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. 60class 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 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 105void 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 113DefaultBrowserInfoBarDelegate::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 131DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() { 132 if (!action_taken_) 133 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1); 134} 135 136int DefaultBrowserInfoBarDelegate::GetIconID() const { 137 return IDR_PRODUCT_LOGO_32; 138} 139 140base::string16 DefaultBrowserInfoBarDelegate::GetMessageText() const { 141 return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT); 142} 143 144base::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 151bool DefaultBrowserInfoBarDelegate::OKButtonTriggersUACPrompt() const { 152 return true; 153} 154 155bool 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 165bool 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 173bool DefaultBrowserInfoBarDelegate::ShouldExpireInternal( 174 const NavigationDetails& details) const { 175 return should_expire_; 176} 177 178void 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 198void 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 213namespace chrome { 214 215void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple* registry) { 216 registry->RegisterStringPref( 217 prefs::kBrowserSuppressDefaultBrowserPrompt, std::string()); 218} 219 220void 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 261#if !defined(OS_WIN) 262bool ShowFirstRunDefaultBrowserPrompt(Profile* profile) { 263 return false; 264} 265#endif 266 267} // namespace chrome 268