default_browser_prompt.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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 delegate and adds it to |infobar_service|. 62 static void Create(InfoBarService* infobar_service, 63 PrefService* prefs, 64 bool interactive_flow_required); 65 66 private: 67 DefaultBrowserInfoBarDelegate(InfoBarService* infobar_service, 68 PrefService* prefs, 69 bool interactive_flow_required); 70 virtual ~DefaultBrowserInfoBarDelegate(); 71 72 void AllowExpiry() { should_expire_ = true; } 73 74 // ConfirmInfoBarDelegate: 75 virtual int GetIconID() const OVERRIDE; 76 virtual string16 GetMessageText() const OVERRIDE; 77 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 78 virtual bool NeedElevation(InfoBarButton button) const OVERRIDE; 79 virtual bool Accept() OVERRIDE; 80 virtual bool Cancel() OVERRIDE; 81 virtual bool ShouldExpireInternal( 82 const content::LoadCommittedDetails& details) const OVERRIDE; 83 84 // The prefs to use. 85 PrefService* prefs_; 86 87 // Whether the user clicked one of the buttons. 88 bool action_taken_; 89 90 // Whether the info-bar should be dismissed on the next navigation. 91 bool should_expire_; 92 93 // Whether changing the default application will require entering the 94 // modal-UI flow. 95 const bool interactive_flow_required_; 96 97 // Used to delay the expiration of the info-bar. 98 base::WeakPtrFactory<DefaultBrowserInfoBarDelegate> weak_factory_; 99 100 DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate); 101}; 102 103// static 104void DefaultBrowserInfoBarDelegate::Create(InfoBarService* infobar_service, 105 PrefService* prefs, 106 bool interactive_flow_required) { 107 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 108 new DefaultBrowserInfoBarDelegate(infobar_service, prefs, 109 interactive_flow_required))); 110} 111 112DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate( 113 InfoBarService* infobar_service, 114 PrefService* prefs, 115 bool interactive_flow_required) 116 : ConfirmInfoBarDelegate(infobar_service), 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 140string16 DefaultBrowserInfoBarDelegate::GetMessageText() const { 141 return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT); 142} 143 144string16 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::NeedElevation(InfoBarButton button) const { 152 return button == BUTTON_OK; 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 content::LoadCommittedDetails& 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