default_browser_prompt.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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_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 34using content::BrowserThread; 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 delegate and adds it to |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 BrowserThread::PostTask( 159 BrowserThread::FILE, 160 FROM_HERE, 161 base::Bind(&SetChromeAsDefaultBrowser, interactive_flow_required_, 162 prefs_)); 163 164 return true; 165} 166 167bool DefaultBrowserInfoBarDelegate::Cancel() { 168 action_taken_ = true; 169 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1); 170 // User clicked "Don't ask me again", remember that. 171 prefs_->SetBoolean(prefs::kCheckDefaultBrowser, false); 172 return true; 173} 174 175bool DefaultBrowserInfoBarDelegate::ShouldExpireInternal( 176 const content::LoadCommittedDetails& details) const { 177 return should_expire_; 178} 179 180void NotifyNotDefaultBrowserCallback(chrome::HostDesktopType desktop_type) { 181 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type); 182 if (!browser) 183 return; // Reached during ui tests. 184 185 // In ChromeBot tests, there might be a race. This line appears to get 186 // called during shutdown and |tab| can be NULL. 187 content::WebContents* web_contents = 188 browser->tab_strip_model()->GetActiveWebContents(); 189 if (!web_contents) 190 return; 191 192 bool interactive_flow = ShellIntegration::CanSetAsDefaultBrowser() == 193 ShellIntegration::SET_DEFAULT_INTERACTIVE; 194 Profile* profile = 195 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 196 DefaultBrowserInfoBarDelegate::Create( 197 InfoBarService::FromWebContents(web_contents), profile->GetPrefs(), 198 interactive_flow); 199} 200 201void CheckDefaultBrowserCallback(chrome::HostDesktopType desktop_type) { 202 if (ShellIntegration::GetDefaultBrowser() == ShellIntegration::NOT_DEFAULT) { 203 ShellIntegration::DefaultWebClientSetPermission default_change_mode = 204 ShellIntegration::CanSetAsDefaultBrowser(); 205 206 if (default_change_mode != ShellIntegration::SET_DEFAULT_NOT_ALLOWED) { 207 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 208 base::Bind(&NotifyNotDefaultBrowserCallback, desktop_type)); 209 } 210 } 211} 212 213} // namespace 214 215namespace chrome { 216 217void RegisterDefaultBrowserPromptPrefs(PrefRegistrySimple* registry) { 218 registry->RegisterStringPref( 219 prefs::kBrowserSuppressDefaultBrowserPrompt, std::string()); 220} 221 222void ShowDefaultBrowserPrompt(Profile* profile, HostDesktopType desktop_type) { 223 // We do not check if we are the default browser if: 224 // - The user said "don't ask me again" on the infobar earlier. 225 // - There is a policy in control of this setting. 226 // - The "suppress_default_browser_prompt_for_version" master preference is 227 // set to the current version. 228 if (!profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser)) 229 return; 230 231 if (g_browser_process->local_state()->IsManagedPreference( 232 prefs::kDefaultBrowserSettingEnabled)) { 233 if (g_browser_process->local_state()->GetBoolean( 234 prefs::kDefaultBrowserSettingEnabled)) { 235 BrowserThread::PostTask( 236 BrowserThread::FILE, FROM_HERE, 237 base::Bind( 238 base::IgnoreResult(&ShellIntegration::SetAsDefaultBrowser))); 239 } else { 240 // TODO(pastarmovj): We can't really do anything meaningful here yet but 241 // just prevent showing the infobar. 242 } 243 return; 244 } 245 246 const std::string disable_version_string = 247 g_browser_process->local_state()->GetString( 248 prefs::kBrowserSuppressDefaultBrowserPrompt); 249 const Version disable_version(disable_version_string); 250 251 DCHECK(disable_version_string.empty() || disable_version.IsValid()); 252 if (disable_version.IsValid()) { 253 const chrome::VersionInfo version_info; 254 const Version chrome_version(version_info.Version()); 255 if (disable_version.Equals(chrome_version)) 256 return; 257 } 258 259 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 260 base::Bind(&CheckDefaultBrowserCallback, 261 desktop_type)); 262 263} 264 265#if !defined(OS_WIN) 266bool ShowFirstRunDefaultBrowserPrompt(Profile* profile) { 267 return false; 268} 269#endif 270 271} // namespace chrome 272