diff options
29 files changed, 577 insertions, 12 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index e090943..b4e9a27 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3625,6 +3625,17 @@ Public Exponent (<ph name="PUBLIC_EXPONENT_NUM_BITS">$3<ex>24</ex></ph> bits): View </message> + <!-- Autolaunch infobar --> + <message name="IDS_AUTO_LAUNCH_INFOBAR_TEXT" desc="The text to show in the infobar when Chrome was automatically launched on startup"> + <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is configured to automatically launch when you start your computer. + </message> + <message name="IDS_AUTO_LAUNCH_OK" desc="Label for OK button on Autolaunch confirmation infobar."> + OK + </message> + <message name="IDS_AUTO_LAUNCH_REVERT" desc="Label for button (on Autolaunch confirmation infobar) that disables autolaunching."> + Cut it out! + </message> + <!-- Basic Auth Dialog --> <message name="IDS_LOGIN_DIALOG_TITLE" desc="String to be displayed in the title bar of the login prompt dialog"> Authentication Required @@ -8192,6 +8203,9 @@ Would you like to start <ph name="CONTROL_PANEL_APPLET_NAME">$1<ex>Add/Remove Pr <message name="IDS_OPTIONS_DEFAULTBROWSER_SXS" desc="The text displayed when Chrome is installed in side-by-side mode, which does not support setting as the default browser."> This is a secondary installation of <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>, and cannot be made your default browser. </message> + <message name="IDS_AUTOLAUNCH_TEXT" desc="The text displayed in settings to explain whether Chrome is set to auto-launch on startup or not."> + Launch <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> automatically when I start my computer + </message> <if expr="pp_ifdef('use_titlecase')"> <message name="IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT" desc="In Title Case: The label of the 'Use Chrome as default' browser button"> diff --git a/chrome/browser/auto_launch_trial.cc b/chrome/browser/auto_launch_trial.cc new file mode 100644 index 0000000..60aa1b2 --- /dev/null +++ b/chrome/browser/auto_launch_trial.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/auto_launch_trial.h" + +#include "base/file_path.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram.h" +#include "chrome/browser/first_run/first_run.h" +#include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/master_preferences.h" + +const char kAutoLaunchTrialName[] = "AutoLaunchExperiment"; +const char kAutoLaunchTrialAutoLaunchGroup[] = "AutoLaunching"; +const char kAutoLaunchTrialControlGroup[] = "NotAutoLaunching"; + +namespace auto_launch_trial { + +bool IsInAutoLaunchGroup() { + return base::FieldTrialList::TrialExists(kAutoLaunchTrialName) && + base::FieldTrialList::Find(kAutoLaunchTrialName)->group_name() + == kAutoLaunchTrialAutoLaunchGroup; +} + +void UpdateToggleAutoLaunchMetric(bool auto_launch) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("ToggleAutoLaunch", kAutoLaunchTrialName), + auto_launch ? 1 : 0, 2); +} + +void UpdateInfobarResponseMetric(InfobarMetricResponse response) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("InfobarRepsonse", kAutoLaunchTrialName), + response, 3); +} + +void UpdateInfobarShownMetric() { + UMA_HISTOGRAM_COUNTS( + base::FieldTrial::MakeName("InfobarShown", kAutoLaunchTrialName), 1); +} + +} // namespace auto_launch_trial diff --git a/chrome/browser/auto_launch_trial.h b/chrome/browser/auto_launch_trial.h new file mode 100644 index 0000000..69a3e9d --- /dev/null +++ b/chrome/browser/auto_launch_trial.h @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTO_LAUNCH_TRIAL_H_ +#define CHROME_BROWSER_AUTO_LAUNCH_TRIAL_H_ +#pragma once + +// Strings used with the "auto launching Chrome at computer startup" trial. If +// the field trial is running then... +// base::FieldTrialList::TrialExists(kAutoLaunchTrial_Name) returns true. +// +// The field trial consists of two groups of users: those that auto-launch +// Chrome at startup and those that don't. The group_name() of the field +// trial object is used to determine the group that the user belongs to. +// +// The field trial is setup in ChromeBrowserMainParts::AutoLaunchFieldTrial() +// based on the user's brand code: +// +// - brand RNGP auto launches Chrome on computer startup. +// - brand RNGQ does not. +// - any other brand code does whatever comes natural to it. + +extern const char kAutoLaunchTrialName[]; +extern const char kAutoLaunchTrialAutoLaunchGroup[]; +extern const char kAutoLaunchTrialControlGroup[]; + +namespace auto_launch_trial { + +// The possible responses for the auto-launch infobar. +enum InfobarMetricResponse { + INFOBAR_CUT_IT_OUT = 0, + INFOBAR_OK, + INFOBAR_IGNORE, +}; + +// Whether the auto-launch experiment is active and the user is part of it. +bool IsInAutoLaunchGroup(); + +// Updates UMA to reflect user changing the auto-launch setting. +void UpdateToggleAutoLaunchMetric(bool auto_launch); + +// Updates UMA to reflect user responses to the infobar. +void UpdateInfobarResponseMetric(InfobarMetricResponse response); + +// Updates UMA to reflect that the infobar has been shown. +void UpdateInfobarShownMetric(); + +} // namespace auto_launch_trial + +#endif // CHROME_BROWSER_AUTO_LAUNCH_TRIAL_H_ diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index ad900d6..3898f57 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -29,6 +29,7 @@ #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/about_flags.h" +#include "chrome/browser/auto_launch_trial.h" #include "chrome/browser/background/background_mode_manager.h" #include "chrome/browser/browser_process_impl.h" #include "chrome/browser/browser_shutdown.h" @@ -1113,6 +1114,20 @@ void ChromeBrowserMainParts::DefaultAppsFieldTrial() { } } +void ChromeBrowserMainParts::AutoLaunchChromeFieldTrial() { + std::string brand; + google_util::GetBrand(&brand); + + // Create a 100% field trial based on the brand code. + if (LowerCaseEqualsASCII(brand, "rngp")) { + base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName, + kAutoLaunchTrialAutoLaunchGroup); + } else if (LowerCaseEqualsASCII(brand, "rngq")) { + base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName, + kAutoLaunchTrialControlGroup); + } +} + // ChromeBrowserMainParts: |SetupMetricsAndFieldTrials()| related -------------- // Initializes the metrics service with the configuration for this process, @@ -1173,6 +1188,7 @@ void ChromeBrowserMainParts::SetupFieldTrials(bool metrics_recording_enabled, WarmConnectionFieldTrial(); PredictorFieldTrial(); DefaultAppsFieldTrial(); + AutoLaunchChromeFieldTrial(); sync_promo_trial::Activate(); } diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h index 26f22a6..491f5d3 100644 --- a/chrome/browser/chrome_browser_main.h +++ b/chrome/browser/chrome_browser_main.h @@ -113,6 +113,10 @@ class ChromeBrowserMainParts : public content::BrowserMainParts { // has on retention and general apps/webstore usage. void DefaultAppsFieldTrial(); + // A field trial to see what effects launching Chrome automatically on + // computer startup has on retention and usage of Chrome. + void AutoLaunchChromeFieldTrial(); + // Methods for |SetupMetricsAndFieldTrials()| -------------------------------- // Constructs metrics service and does related initialization, including diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 9b4a6b3..b113259 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc @@ -52,6 +52,7 @@ #include "chrome/browser/translate/translate_prefs.h" #include "chrome/browser/ui/alternate_error_tab_observer.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_init.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "chrome/browser/ui/search_engines/keyword_editor_controller.h" #include "chrome/browser/ui/webui/flags_ui.h" @@ -153,6 +154,7 @@ void RegisterUserPrefs(PrefService* user_prefs) { SessionStartupPref::RegisterUserPrefs(user_prefs); BookmarkModel::RegisterUserPrefs(user_prefs); Browser::RegisterUserPrefs(user_prefs); + BrowserInit::RegisterUserPrefs(user_prefs); PasswordManager::RegisterUserPrefs(user_prefs); chrome_browser_net::Predictor::RegisterUserPrefs(user_prefs); DownloadPrefs::RegisterUserPrefs(user_prefs); diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 2af7b17..4d06327 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html @@ -121,6 +121,13 @@ i18n-content="defaultBrowserUseAsDefault"></button> <div id="defaultBrowserState" i18n-content="defaultBrowserUnknown"></div> + <div id="autoLaunchOption" class="checkbox" hidden> + <label> + <input id="autoLaunch" type="checkbox"> + <span i18n-content="autoLaunchText"></span> + </input> + </label> + </div> </div> </section> </if> diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index ba59d3d..294bb9d 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js @@ -113,6 +113,9 @@ cr.define('options', function() { $('defaultBrowserUseAsDefaultButton').onclick = function(event) { chrome.send('becomeDefaultBrowser'); }; + + $('autoLaunch').addEventListener('click', + this.handleAutoLaunchChanged_); } var startupPagesList = $('startupPagesList'); @@ -282,7 +285,7 @@ cr.define('options', function() { }, /** - * Handle change events of the preference + * Handles change events of the preference * 'session.urls_to_restore_on_startup'. * @param {event} preference changed event. * @private @@ -293,7 +296,7 @@ cr.define('options', function() { }, /** - * Set the default search engine based on the popup selection. + * Sets the default search engine based on the popup selection. */ setDefaultSearchEngine_: function() { var engineSelect = $('defaultSearchEngine'); @@ -305,6 +308,13 @@ cr.define('options', function() { }, /** + * Sets or clear whether Chrome should Auto-launch on computer startup. + */ + handleAutoLaunchChanged_: function() { + chrome.send('toggleAutoLaunch', [Boolean($('autoLaunch').checked)]); + }, + + /** * Sends an asynchronous request for new autocompletion suggestions for the * the given query. When new suggestions are available, the C++ handler will * call updateAutocompleteSuggestions_. @@ -329,6 +339,14 @@ cr.define('options', function() { return; list.suggestions = suggestions; }, + + /** + * Shows the autoLaunch preference and initializes its checkbox value. + */ + updateAutoLaunchState_: function(enabled) { + $('autoLaunchOption').hidden = false; + $('autoLaunch').checked = enabled; + }, }; BrowserOptions.updateDefaultBrowserState = function(statusString, isDefault, @@ -354,6 +372,10 @@ cr.define('options', function() { BrowserOptions.getInstance().updateAutocompleteSuggestions_(suggestions); }; + BrowserOptions.updateAutoLaunchState = function(enabled) { + BrowserOptions.getInstance().updateAutoLaunchState_(enabled); + }; + BrowserOptions.setInstantFieldTrialStatus = function(enabled) { BrowserOptions.getInstance().setInstantFieldTrialStatus_(enabled); }; diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc index a6555eb..23c05e1 100644 --- a/chrome/browser/ui/browser_init.cc +++ b/chrome/browser/ui/browser_init.cc @@ -20,6 +20,7 @@ #include "base/string_split.h" #include "base/threading/thread_restrictions.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/auto_launch_trial.h" #include "chrome/browser/automation/automation_provider.h" #include "chrome/browser/automation/automation_provider_list.h" #include "chrome/browser/automation/chrome_frame_automation_provider.h" @@ -116,10 +117,127 @@ #include "ui/base/touch/touch_factory.h" #endif +#if defined(OS_WIN) +#include "chrome/installer/util/auto_launch_util.h" +#endif + using content::BrowserThread; namespace { +static const int kMaxInfobarShown = 5; + +#if defined(OS_WIN) +// The delegate for the infobar shown when Chrome was auto-launched. +class AutolaunchInfoBarDelegate : public ConfirmInfoBarDelegate { + public: + AutolaunchInfoBarDelegate(InfoBarTabHelper* infobar_helper, + PrefService* prefs); + virtual ~AutolaunchInfoBarDelegate(); + + private: + void AllowExpiry() { should_expire_ = true; } + + // ConfirmInfoBarDelegate: + virtual bool ShouldExpire( + const content::LoadCommittedDetails& details) const OVERRIDE; + virtual gfx::Image* GetIcon() const OVERRIDE; + virtual string16 GetMessageText() const OVERRIDE; + virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; + virtual bool Accept() OVERRIDE; + virtual bool Cancel() OVERRIDE; + + // The prefs to use. + PrefService* prefs_; + + // Whether the user clicked one of the buttons. + bool action_taken_; + + // Whether the info-bar should be dismissed on the next navigation. + bool should_expire_; + + // Used to delay the expiration of the info-bar. + base::WeakPtrFactory<AutolaunchInfoBarDelegate> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AutolaunchInfoBarDelegate); +}; + +AutolaunchInfoBarDelegate::AutolaunchInfoBarDelegate( + InfoBarTabHelper* infobar_helper, + PrefService* prefs) + : ConfirmInfoBarDelegate(infobar_helper), + prefs_(prefs), + action_taken_(false), + should_expire_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { + auto_launch_trial::UpdateInfobarShownMetric(); + + int count = prefs_->GetInteger(prefs::kShownAutoLaunchInfobar); + prefs_->SetInteger(prefs::kShownAutoLaunchInfobar, count + 1); + + // We want the info-bar to stick-around for a few seconds and then be hidden + // on the next navigation after that. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&AutolaunchInfoBarDelegate::AllowExpiry, + weak_factory_.GetWeakPtr()), + 8000); // 8 seconds. +} + +AutolaunchInfoBarDelegate::~AutolaunchInfoBarDelegate() { + if (!action_taken_) { + auto_launch_trial::UpdateInfobarResponseMetric( + auto_launch_trial::INFOBAR_IGNORE); + } +} + +bool AutolaunchInfoBarDelegate::ShouldExpire( + const content::LoadCommittedDetails& details) const { + return details.is_navigation_to_different_page() && should_expire_; +} + +gfx::Image* AutolaunchInfoBarDelegate::GetIcon() const { + return &ResourceBundle::GetSharedInstance().GetNativeImageNamed( + IDR_PRODUCT_LOGO_32); +} + +string16 AutolaunchInfoBarDelegate::GetMessageText() const { + return l10n_util::GetStringFUTF16(IDS_AUTO_LAUNCH_INFOBAR_TEXT, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); +} + +string16 AutolaunchInfoBarDelegate::GetButtonLabel( + InfoBarButton button) const { + return l10n_util::GetStringUTF16((button == BUTTON_OK) ? + IDS_AUTO_LAUNCH_OK : IDS_AUTO_LAUNCH_REVERT); +} + +bool AutolaunchInfoBarDelegate::Accept() { + action_taken_ = true; + auto_launch_trial::UpdateInfobarResponseMetric( + auto_launch_trial::INFOBAR_OK); + return true; +} + +bool AutolaunchInfoBarDelegate::Cancel() { + action_taken_ = true; + + // Track infobar reponse. + auto_launch_trial::UpdateInfobarResponseMetric( + auto_launch_trial::INFOBAR_CUT_IT_OUT); + // Also make sure we keep track of how many disable and how many enable. + const bool auto_launch = false; + auto_launch_trial::UpdateToggleAutoLaunchMetric(auto_launch); + + content::BrowserThread::PostTask( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&auto_launch_util::SetWillLaunchAtLogin, + auto_launch, FilePath())); + return true; +} + +#endif // OS_WIN + // DefaultBrowserInfoBarDelegate ---------------------------------------------- // The delegate for the infobar shown when Chrome is not the default browser. @@ -223,6 +341,26 @@ bool DefaultBrowserInfoBarDelegate::Cancel() { return true; } +#if defined(OS_WIN) +void CheckAutoLaunchCallback() { + if (!auto_launch_trial::IsInAutoLaunchGroup()) + return; + + Browser* browser = BrowserList::GetLastActive(); + TabContentsWrapper* tab = browser->GetSelectedTabContentsWrapper(); + + int infobar_shown = + tab->profile()->GetPrefs()->GetInteger(prefs::kShownAutoLaunchInfobar); + if (infobar_shown >= kMaxInfobarShown) + return; + + InfoBarTabHelper* infobar_helper = tab->infobar_tab_helper(); + infobar_helper->AddInfoBar( + new AutolaunchInfoBarDelegate(infobar_helper, + tab->profile()->GetPrefs())); +} +#endif + void NotifyNotDefaultBrowserCallback() { Browser* browser = BrowserList::GetLastActive(); if (!browser) @@ -517,6 +655,12 @@ bool BrowserInit::InProcessStartup() { return in_startup; } +// static +void BrowserInit::RegisterUserPrefs(PrefService* prefs) { + prefs->RegisterIntegerPref( + prefs::kShownAutoLaunchInfobar, 0, PrefService::UNSYNCABLE_PREF); +} + bool BrowserInit::LaunchBrowser(const CommandLine& command_line, Profile* profile, const FilePath& cur_dir, @@ -699,6 +843,8 @@ bool BrowserInit::LaunchWithProfile::Launch( if (process_startup) { if (browser_defaults::kOSSupportsOtherBrowsers && !command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) { + CheckIfAutoLaunched(profile); + // Check whether we are the default browser. CheckDefaultBrowser(profile); } @@ -1309,6 +1455,19 @@ void BrowserInit::LaunchWithProfile::CheckDefaultBrowser(Profile* profile) { BrowserThread::FILE, FROM_HERE, base::Bind(&CheckDefaultBrowserCallback)); } +void BrowserInit::LaunchWithProfile::CheckIfAutoLaunched(Profile* profile) { +#if defined(OS_WIN) + if (!auto_launch_trial::IsInAutoLaunchGroup()) + return; + + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kAutoLaunchAtStartup)) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&CheckAutoLaunchCallback)); + } +#endif +} + std::vector<GURL> BrowserInit::GetURLsFromCommandLine( const CommandLine& command_line, const FilePath& cur_dir, diff --git a/chrome/browser/ui/browser_init.h b/chrome/browser/ui/browser_init.h index 9e2ebfc..7d5a332 100644 --- a/chrome/browser/ui/browser_init.h +++ b/chrome/browser/ui/browser_init.h @@ -18,6 +18,7 @@ class Browser; class CommandLine; class GURL; +class PrefService; class TabContentsWrapper; // class containing helpers for BrowserMain to spin up a new instance and @@ -62,6 +63,8 @@ class BrowserInit { // Returns true if the browser is coming up. static bool InProcessStartup(); + static void RegisterUserPrefs(PrefService* prefs); + // Launches a browser window associated with |profile|. |command_line| should // be the command line passed to this process. |cur_dir| can be empty, which // implies that the directory of the executable should be used. @@ -224,6 +227,9 @@ class BrowserInit { // previously instructed not to do so) and warns the user if it is not. void CheckDefaultBrowser(Profile* profile); + // Checks whether Chrome was auto-started at login. + void CheckIfAutoLaunched(Profile* profile); + const FilePath cur_dir_; const CommandLine& command_line_; Profile* profile_; diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index 3546734..653efbd 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc @@ -8,9 +8,11 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/memory/singleton.h" +#include "base/path_service.h" #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "base/values.h" +#include "chrome/browser/auto_launch_trial.h" #include "chrome/browser/autocomplete/autocomplete.h" #include "chrome/browser/autocomplete/autocomplete_match.h" #include "chrome/browser/browser_process.h" @@ -37,10 +39,18 @@ #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" +#if defined(OS_WIN) +#include "chrome/installer/util/auto_launch_util.h" +#endif + +using content::BrowserThread; using content::UserMetricsAction; BrowserOptionsHandler::BrowserOptionsHandler() - : template_url_service_(NULL), startup_custom_pages_table_model_(NULL) { + : template_url_service_(NULL), + startup_custom_pages_table_model_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_for_file_(this)), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_for_ui_(this)) { #if !defined(OS_MACOSX) default_browser_worker_ = new ShellIntegration::DefaultBrowserWorker(this); #endif @@ -92,6 +102,9 @@ void BrowserOptionsHandler::GetLocalizedValues( localized_strings->SetString("defaultBrowserUseAsDefault", l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + localized_strings->SetString("autoLaunchText", + l10n_util::GetStringFUTF16(IDS_AUTOLAUNCH_TEXT, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); } void BrowserOptionsHandler::RegisterMessages() { @@ -154,6 +167,47 @@ void BrowserOptionsHandler::Initialize() { UpdateSearchEngines(); autocomplete_controller_.reset(new AutocompleteController(profile, this)); + +#if defined(OS_WIN) + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&BrowserOptionsHandler::CheckAutoLaunch, + weak_ptr_factory_for_ui_.GetWeakPtr(), + weak_ptr_factory_for_file_.GetWeakPtr())); + weak_ptr_factory_for_ui_.DetachFromThread(); +#endif +} + +void BrowserOptionsHandler::CheckAutoLaunch( + base::WeakPtr<BrowserOptionsHandler> weak_this) { +#if defined(OS_WIN) + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + // Pass in weak pointer to this to avoid race if BrowserOptionsHandler is + // deleted. + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&BrowserOptionsHandler::CheckAutoLaunchCallback, + weak_this, + auto_launch_trial::IsInAutoLaunchGroup(), + auto_launch_util::WillLaunchAtLogin(FilePath()))); +#endif +} + +void BrowserOptionsHandler::CheckAutoLaunchCallback( + bool is_in_auto_launch_group, + bool will_launch_at_login) { +#if defined(OS_WIN) + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (is_in_auto_launch_group) { + web_ui_->RegisterMessageCallback("toggleAutoLaunch", + base::Bind(&BrowserOptionsHandler::ToggleAutoLaunch, + base::Unretained(this))); + + base::FundamentalValue enabled(will_launch_at_login); + web_ui_->CallJavascriptFunction("BrowserOptions.updateAutoLaunchState", + enabled); + } +#endif } void BrowserOptionsHandler::UpdateDefaultBrowserState() { @@ -463,6 +517,23 @@ void BrowserOptionsHandler::DisableInstant(const ListValue* args) { InstantController::Disable(Profile::FromWebUI(web_ui_)); } +void BrowserOptionsHandler::ToggleAutoLaunch(const ListValue* args) { +#if defined(OS_WIN) + if (!auto_launch_trial::IsInAutoLaunchGroup()) + return; + + bool enable; + CHECK_EQ(args->GetSize(), 1U); + CHECK(args->GetBoolean(0, &enable)); + + // Make sure we keep track of how many disable and how many enable. + auto_launch_trial::UpdateToggleAutoLaunchMetric(enable); + content::BrowserThread::PostTask( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&auto_launch_util::SetWillLaunchAtLogin, enable, FilePath())); +#endif // OS_WIN +} + void BrowserOptionsHandler::GetInstantFieldTrialStatus(const ListValue* args) { Profile* profile = Profile::FromWebUI(web_ui_); base::FundamentalValue enabled( diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h index 44aec51..ce64322 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.h +++ b/chrome/browser/ui/webui/options/browser_options_handler.h @@ -8,6 +8,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h" #include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/browser/prefs/pref_member.h" @@ -89,6 +90,22 @@ class BrowserOptionsHandler : public OptionsPageUIHandler, void EnableInstant(const ListValue* args); void DisableInstant(const ListValue* args); + // Enables/disables auto-launching of Chrome on computer startup. + void ToggleAutoLaunch(const ListValue* args); + + // Checks (on the file thread) whether the user is in the auto-launch trial + // and whether Chrome is set to auto-launch at login. Gets a reply on the UI + // thread (see CheckAutoLaunchCallback). A weak pointer to this is passed in + // as a parameter to avoid the need to lock between this function and the + // destructor. + + void CheckAutoLaunch(base::WeakPtr<BrowserOptionsHandler> weak_this); + // Sets up (on the UI thread) the necessary bindings for toggling auto-launch + // (if the user is part of the auto-launch and makes sure the HTML UI knows + // whether Chrome will auto-launch at login. + void CheckAutoLaunchCallback(bool is_in_auto_launch_group, + bool will_launch_at_login); + // Called to request information about the Instant field trial. void GetInstantFieldTrialStatus(const ListValue* args); @@ -130,6 +147,11 @@ class BrowserOptionsHandler : public OptionsPageUIHandler, scoped_ptr<AutocompleteController> autocomplete_controller_; + // Used to get |weak_ptr_| to self for use on the File thread. + base::WeakPtrFactory<BrowserOptionsHandler> weak_ptr_factory_for_file_; + // Used to post update tasks to the UI thread. + base::WeakPtrFactory<BrowserOptionsHandler> weak_ptr_factory_for_ui_; + DISALLOW_COPY_AND_ASSIGN(BrowserOptionsHandler); }; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 3742c83..b7b12f1 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -204,6 +204,8 @@ 'browser/autofill/phone_number_i18n.h', 'browser/autofill/select_control_handler.cc', 'browser/autofill/select_control_handler.h', + 'browser/auto_launch_trial.cc', + 'browser/auto_launch_trial.h', 'browser/automation/automation_browser_tracker.cc', 'browser/automation/automation_browser_tracker.h', 'browser/automation/automation_extension_tracker.cc', diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi index 450ff7b..a8a0149 100644 --- a/chrome/chrome_installer_util.gypi +++ b/chrome/chrome_installer_util.gypi @@ -15,6 +15,8 @@ 'installer/util/app_command.h', 'installer/util/app_commands.cc', 'installer/util/app_commands.h', + 'installer/util/auto_launch_util.cc', + 'installer/util/auto_launch_util.h', 'installer/util/browser_distribution.cc', 'installer/util/browser_distribution.h', 'installer/util/channel_info.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 69f28d8..8a15341 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -105,13 +105,17 @@ const char kAuthNegotiateDelegateWhitelist[] = // HTTP authentication schemes to enable. This is a comma-separated list of // authentication schemes (basic, digest, ntlm, and negotiate). By default all // schemes are enabled. The primary use of this command line flag is to help -// triage autentication-related issues reported by end-users. +// triage authentication-related issues reported by end-users. const char kAuthSchemes[] = "auth-schemes"; // Whitelist of servers which NTLM and Negotiate can automatically authenticate // with using the default credentials of the currently logged in user. const char kAuthServerWhitelist[] = "auth-server-whitelist"; +// A flag that is used to tell Chrome that it was launched automatically at +// computer startup and not by some user action. +const char kAutoLaunchAtStartup[] = "auto-launch-at-startup"; + // The value of this switch tells the app to listen for and broadcast // automation-related messages on IPC channel with the given ID. const char kAutomationClientChannelID[] = "automation-channel"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index e986f20..1d57efa 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -47,6 +47,7 @@ extern const char kAppsNoThrob[]; extern const char kAuthNegotiateDelegateWhitelist[]; extern const char kAuthSchemes[]; extern const char kAuthServerWhitelist[]; +extern const char kAutoLaunchAtStartup[]; extern const char kAutomationClientChannelID[]; extern const char kAutomationReinitializeOnChannelError[]; extern const char kCheckForUpdateIntervalSec[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 0b74a90..52155e2 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1524,6 +1524,10 @@ const char kCloudPrintSigninDialogHeight[] = // launches. const char kRegisteredBackgroundContents[] = "background_contents.registered"; +// An int that stores how often we've shown the "Chrome is configured to +// auto-launch" infobar. +const char kShownAutoLaunchInfobar[] = "browser.shown_autolaunch_infobar"; + // String that lists supported HTTP authentication schemes. const char kAuthSchemes[] = "auth.schemes"; diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index dc9d902..5645621a 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -607,6 +607,8 @@ extern const char kChromeOsReleaseChannel[]; extern const char kRegisteredBackgroundContents[]; +extern const char kShownAutoLaunchInfobar[]; + extern const char kAuthSchemes[]; extern const char kDisableAuthNegotiateCnameLookup[]; extern const char kEnableAuthNegotiatePort[]; diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 0fa8859..464e69c 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -18,6 +18,7 @@ #include "base/utf_string_conversions.h" #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/setup/install_worker.h" +#include "chrome/installer/util/auto_launch_util.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/create_reg_key_work_item.h" #include "chrome/installer/util/delete_after_reboot_helper.h" @@ -411,6 +412,20 @@ InstallStatus InstallOrUpdateProduct( RegisterChromeOnMachine(installer_state, *chrome_install, make_chrome_default || force_chrome_default_for_user); + + if (result == FIRST_INSTALL_SUCCESS) { + installer_state.UpdateStage(installer::CONFIGURE_AUTO_LAUNCH); + + // Add auto-launch key if specified in master preferences. + bool auto_launch_chrome = false; + prefs.GetBool( + installer::master_preferences::kAutoLaunchChrome, + &auto_launch_chrome); + if (auto_launch_chrome) { + auto_launch_util::SetWillLaunchAtLogin( + true, installer_state.target_path()); + } + } } installer_state.UpdateStage(installer::REMOVING_OLD_VERSIONS); diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 6538eab..08f53b7 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -22,6 +22,7 @@ #include "chrome/installer/setup/install_worker.h" #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/setup/setup_util.h" +#include "chrome/installer/util/auto_launch_util.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/delete_after_reboot_helper.h" @@ -734,9 +735,13 @@ InstallStatus UninstallProduct(const InstallationState& original_state, // Chrome is not in use so lets uninstall Chrome by deleting various files // and registry entries. Here we will just make best effort and keep going // in case of errors. - if (is_chrome) + if (is_chrome) { ClearRlzProductState(); + if (auto_launch_util::WillLaunchAtLogin(installer_state.target_path())) + auto_launch_util::SetWillLaunchAtLogin(false, FilePath()); + } + // First delete shortcuts from Start->Programs, Desktop & Quick Launch. DeleteChromeShortcuts(installer_state, product); diff --git a/chrome/installer/util/auto_launch_util.cc b/chrome/installer/util/auto_launch_util.cc new file mode 100644 index 0000000..1a80a23 --- /dev/null +++ b/chrome/installer/util/auto_launch_util.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/auto_launch_util.h" + +#include "base/file_path.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "base/win/win_util.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/installer/util/util_constants.h" + +namespace auto_launch_util { + +// The name of the Chrome Auto-launch key under the Run key. +const wchar_t kAutolaunchKeyValue[] = L"GoogleChromeAutoLaunch"; + +bool WillLaunchAtLogin(const FilePath& application_path) { + string16 autolaunch; + if (!base::win::ReadCommandFromAutoRun( + HKEY_CURRENT_USER, kAutolaunchKeyValue, &autolaunch)) { + return false; + } + + FilePath chrome_exe(application_path); + if (chrome_exe.empty()) { + if (!PathService::Get(base::DIR_EXE, &chrome_exe)) { + NOTREACHED(); + return false; + } + } + chrome_exe = chrome_exe.Append(installer::kChromeExe); + + return autolaunch.find(chrome_exe.value()) != string16::npos; +} + +void SetWillLaunchAtLogin(bool auto_launch, const FilePath& application_path) { + // TODO(finnur): Convert this into a shortcut, instead of using the Run key. + if (auto_launch) { + FilePath path(application_path); + if (path.empty()) { + if (!PathService::Get(base::DIR_EXE, &path)) { + NOTREACHED(); + return; + } + } + string16 cmd_line = ASCIIToUTF16("\""); + cmd_line += path.value(); + cmd_line += ASCIIToUTF16("\\"); + cmd_line += installer::kChromeExe; + cmd_line += ASCIIToUTF16("\" --"); + cmd_line += ASCIIToUTF16(switches::kAutoLaunchAtStartup); + + base::win::AddCommandToAutoRun( + HKEY_CURRENT_USER, kAutolaunchKeyValue, cmd_line); + } else { + base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kAutolaunchKeyValue); + } +} + +} // namespace auto_launch_util diff --git a/chrome/installer/util/auto_launch_util.h b/chrome/installer/util/auto_launch_util.h new file mode 100644 index 0000000..3684e8c --- /dev/null +++ b/chrome/installer/util/auto_launch_util.h @@ -0,0 +1,31 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_AUTO_LAUNCH_UTIL_H_ +#define CHROME_INSTALLER_UTIL_AUTO_LAUNCH_UTIL_H_ +#pragma once + +class FilePath; + +// A namespace containing the platform specific implementation of setting Chrome +// to launch on computer startup. +namespace auto_launch_util { + +// Returns whether the Chrome executable specified in |application_path| is set +// to auto-launch at computer startup. NOTE: |application_path| is optional and +// should be blank in most cases (as it will default to the application path of +// the current executable). +bool WillLaunchAtLogin(const FilePath& application_path); + +// Configures whether the Chrome executable should auto-launch at computer +// startup. |application_path| is needed when |auto_launch| is true AND when +// the caller is not the process being set to auto-launch, ie. the installer. +// This is because |application_path|, if left blank, defaults to the +// application path of the current executable. If |auto_launch| is true, then it +// will auto-launch, otherwise it will be configured not to. +void SetWillLaunchAtLogin(bool auto_launch, const FilePath& application_path); + +} // namespace auto_launch_util + +#endif // CHROME_INSTALLER_UTIL_AUTO_LAUNCH_UTIL_H_ diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index f14f372..3479bf8 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -39,6 +39,7 @@ namespace { const wchar_t kStageBinaryPatching[] = L"binary_patching"; const wchar_t kStageBuilding[] = L"building"; +const wchar_t kStageConfiguringAutoLaunch[] = L"configuring_auto_launch"; const wchar_t kStageCopyingPreferencesFile[] = L"copying_prefs"; const wchar_t kStageCreatingShortcuts[] = L"creating_shortcuts"; const wchar_t kStageEnsemblePatching[] = L"ensemble_patching"; @@ -69,7 +70,8 @@ const wchar_t* const kStages[] = { kStageCreatingShortcuts, kStageRegisteringChrome, kStageRemovingOldVersions, - kStageFinishing + kStageFinishing, + kStageConfiguringAutoLaunch, }; COMPILE_ASSERT(installer::NUM_STAGES == arraysize(kStages), @@ -173,7 +175,8 @@ Version* InstallUtil::GetChromeVersion(BrowserDistribution* dist, DCHECK(dist); RegKey key; HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - LONG result = key.Open(reg_root, dist->GetVersionKey().c_str(), KEY_READ); + LONG result = key.Open(reg_root, dist->GetVersionKey().c_str(), + KEY_QUERY_VALUE); std::wstring version_str; if (result == ERROR_SUCCESS) diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc index cce0d2f..f004333 100644 --- a/chrome/installer/util/master_preferences.cc +++ b/chrome/installer/util/master_preferences.cc @@ -135,6 +135,8 @@ void MasterPreferences::InitializeFromCommandLine(const CommandLine& cmd_line) { const char* cmd_line_switch; const char* distribution_switch; } translate_switches[] = { + { installer::switches::kAutoLaunchChrome, + installer::master_preferences::kAutoLaunchChrome }, { installer::switches::kCeee, installer::master_preferences::kCeee }, { installer::switches::kChrome, diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h index 28175c5..2c7a068 100644 --- a/chrome/installer/util/master_preferences.h +++ b/chrome/installer/util/master_preferences.h @@ -39,6 +39,7 @@ const char kDefaultMasterPrefs[] = "master_preferences"; // { // "distribution": { // "alternate_shortcut_text": false, +// "auto_launch_chrome": false, // "oem_bubble": false, // "chrome_shortcut_icon_index": 0, // "create_all_shortcuts": true, diff --git a/chrome/installer/util/master_preferences_constants.cc b/chrome/installer/util/master_preferences_constants.cc index cea5b7f..c1c353f 100644 --- a/chrome/installer/util/master_preferences_constants.cc +++ b/chrome/installer/util/master_preferences_constants.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,7 @@ namespace installer { namespace master_preferences { const char kAltFirstRunBubble[] = "oem_bubble"; const char kAltShortcutText[] = "alternate_shortcut_text"; + const char kAutoLaunchChrome[] = "auto_launch_chrome"; const char kCeee[] = "ceee"; const char kChrome[] = "chrome"; const char kChromeFrame[] = "chrome_frame"; diff --git a/chrome/installer/util/master_preferences_constants.h b/chrome/installer/util/master_preferences_constants.h index cd3d034..fb0acd89 100644 --- a/chrome/installer/util/master_preferences_constants.h +++ b/chrome/installer/util/master_preferences_constants.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -13,13 +13,16 @@ namespace installer { namespace master_preferences { // All the preferences below are expected to be inside the JSON "distribution" // block. Some of them also have equivalent command line option. If same option -// is specified in master preference as well as command line, the commnd line +// is specified in master preference as well as command line, the command line // value takes precedence. // Boolean. Use alternate text for the shortcut. Cmd line override present. extern const char kAltShortcutText[]; // Boolean. Use alternate smaller first run info bubble. extern const char kAltFirstRunBubble[]; +// Boolean. Whether to instruct the installer to auto-launch chrome on computer +// startup. The default (if not provided) is |false|. +extern const char kAutoLaunchChrome[]; // Boolean. CEEE features of Chrome Frame should be enabled as part of // the install. Requires kChromeFrame to be specified as well. extern const char kCeee[]; diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc index 72943a8..9dab113 100644 --- a/chrome/installer/util/util_constants.cc +++ b/chrome/installer/util/util_constants.cc @@ -8,6 +8,9 @@ namespace installer { namespace switches { +// Whether to set Chrome to launch at computer startup. +const char kAutoLaunchChrome[] = "auto-launch-chrome"; + // Install CEEE. const char kCeee[] = "ceee"; diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index 5911701..066edb8f 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -92,6 +92,9 @@ enum ArchiveType { }; // Stages of an installation reported through Google Update on failure. +// The order and value of existing enums must not change. Please add new +// values to the end (before NUM_STAGES) and update the compile assert below +// to assert on the last value added. enum InstallerStage { NO_STAGE, // 0: No stage to report. PRECONDITIONS, // 1: Evaluating pre-install conditions. @@ -109,15 +112,17 @@ enum InstallerStage { REGISTERING_CHROME, // 13: Performing Chrome registration. REMOVING_OLD_VERSIONS, // 14: Deleting old version directories. FINISHING, // 15: Finishing the install. - NUM_STAGES // 16: The number of stages. + CONFIGURE_AUTO_LAUNCH, // 16: Configuring Chrome to auto-launch. + NUM_STAGES // 17: The number of stages. }; // When we start reporting the numerical values from the enum, the order // above MUST be preserved. -COMPILE_ASSERT(FINISHING == 15, +COMPILE_ASSERT(CONFIGURE_AUTO_LAUNCH == 16, never_ever_ever_change_InstallerStage_values_bang); namespace switches { +extern const char kAutoLaunchChrome[]; extern const char kCeee[]; extern const char kChrome[]; extern const char kChromeFrame[]; |