diff options
author | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-26 14:16:48 +0000 |
---|---|---|
committer | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-26 14:16:48 +0000 |
commit | 7867996916cc0ca3d1d89d26c15bb7b39e994419 (patch) | |
tree | 89c2fb2fc2f5d41574d70d2fbf1ad93f7a858f1c /chrome/browser | |
parent | d83e5704eeb51d6e9fec081c00a618ad852abe35 (diff) | |
download | chromium_src-7867996916cc0ca3d1d89d26c15bb7b39e994419.zip chromium_src-7867996916cc0ca3d1d89d26c15bb7b39e994419.tar.gz chromium_src-7867996916cc0ca3d1d89d26c15bb7b39e994419.tar.bz2 |
Enable EULA dialog to be shown from metro Chrome.
BUG=131033
TEST=Run Chrome in Metro mode while the EULA dialog still needs to be accepted. Get kicked back to the desktop to accept the dialog. On accept, get kicked back into metro mode.
Review URL: https://chromiumcodereview.appspot.com/10837222
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158797 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/chrome_browser_main.cc | 10 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run.h | 17 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_posix.cc | 15 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_win.cc | 119 | ||||
-rw-r--r-- | chrome/browser/process_singleton_win.cc | 4 | ||||
-rw-r--r-- | chrome/browser/shell_integration_win.cc | 7 |
6 files changed, 105 insertions, 67 deletions
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index d40fb0d..b0e2f70 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -821,8 +821,14 @@ int ChromeBrowserMainParts::PreCreateThreadsImpl() { // is initialized. first_run_ui_bypass_ = false; // True to skip first run UI. if (is_first_run_) { - first_run_ui_bypass_ = !first_run::ProcessMasterPreferences( - user_data_dir_, master_prefs_.get()); + first_run::ProcessMasterPreferencesResult pmp_result = + first_run::ProcessMasterPreferences(user_data_dir_, + master_prefs_.get()); + if (pmp_result == first_run::EULA_EXIT_NOW) + return chrome::RESULT_CODE_EULA_REFUSED; + + first_run_ui_bypass_ = (pmp_result == first_run::SKIP_FIRST_RUN); + AddFirstRunNewTabs(browser_creator_.get(), master_prefs_->new_tabs); // If we are running in App mode, we do not want to show the importer diff --git a/chrome/browser/first_run/first_run.h b/chrome/browser/first_run/first_run.h index 34c3deb..1e57550 100644 --- a/chrome/browser/first_run/first_run.h +++ b/chrome/browser/first_run/first_run.h @@ -38,6 +38,12 @@ enum FirstRunBubbleMetric { NUM_FIRST_RUN_BUBBLE_METRICS }; +enum ProcessMasterPreferencesResult { + SHOW_FIRST_RUN = 0, // Should show the first run flow. + SKIP_FIRST_RUN, // Should skip the first run flow. + EULA_EXIT_NOW, // Should immediately exit due to EULA flow. +}; + // See ProcessMasterPreferences for more info about this structure. struct MasterPrefs { MasterPrefs(); @@ -107,17 +113,18 @@ FilePath MasterPrefsPath(); // 'Default\Preferences' file. This function locates this file from a standard // location and processes it so it becomes the default preferences in the // profile pointed to by |user_data_dir|. After processing the file, the -// function returns true if and only if showing the first run dialog is -// needed. The detailed settings in the preference file are reported via -// |preference_details|. +// function returns a value from the ProcessMasterPreferencesResult enum, +// indicating whether the first run flow should be shown, skipped, or whether +// the browser should exit. // // This function destroys any existing prefs file and it is meant to be // invoked only on first run. // // See chrome/installer/util/master_preferences.h for a description of // 'master_preferences' file. -bool ProcessMasterPreferences(const FilePath& user_data_dir, - MasterPrefs* out_prefs); +ProcessMasterPreferencesResult ProcessMasterPreferences( + const FilePath& user_data_dir, + MasterPrefs* out_prefs); // Show the first run search engine bubble at the first appropriate opportunity. // This bubble may be delayed by other UI, like global errors and sync promos. diff --git a/chrome/browser/first_run/first_run_posix.cc b/chrome/browser/first_run/first_run_posix.cc index e5e0132..6724ec2 100644 --- a/chrome/browser/first_run/first_run_posix.cc +++ b/chrome/browser/first_run/first_run_posix.cc @@ -127,22 +127,23 @@ int ImportNow(Profile* profile, const CommandLine& cmdline) { return internal::ImportBookmarkFromFileIfNeeded(profile, cmdline); } -bool ProcessMasterPreferences(const FilePath& user_data_dir, - MasterPrefs* out_prefs) { +ProcessMasterPreferencesResult ProcessMasterPreferences( + const FilePath& user_data_dir, + MasterPrefs* out_prefs) { DCHECK(!user_data_dir.empty()); FilePath master_prefs_path; scoped_ptr<installer::MasterPreferences> install_prefs(internal::LoadMasterPrefs(&master_prefs_path)); if (!install_prefs.get()) - return true; + return SHOW_FIRST_RUN; out_prefs->new_tabs = install_prefs->GetFirstRunTabs(); internal::SetRLZPref(out_prefs, install_prefs.get()); if (!internal::CopyPrefFile(user_data_dir, master_prefs_path)) - return true; + return SHOW_FIRST_RUN; internal::SetupMasterPrefsFromInstallPrefs(out_prefs, install_prefs.get()); @@ -152,7 +153,7 @@ bool ProcessMasterPreferences(const FilePath& user_data_dir, // Note we are skipping all other master preferences if skip-first-run-ui // is *not* specified. (That is, we continue only if skipping first run ui.) if (!internal::SkipFirstRunUI(install_prefs.get())) - return true; + return SHOW_FIRST_RUN; // From here on we won't show first run so we need to do the work to show the // bubble anyway, unless it's already been explicitly suppressed. @@ -162,13 +163,13 @@ bool ProcessMasterPreferences(const FilePath& user_data_dir, // proceed because ImportSettings will launch the importer process which // would end up here if the sentinel is not present. if (!CreateSentinel()) - return false; + return SKIP_FIRST_RUN; internal::SetShowWelcomePagePrefIfNeeded(install_prefs.get()); internal::SetImportPreferencesAndLaunchImport(out_prefs, install_prefs.get()); internal::SetDefaultBrowser(install_prefs.get()); - return false; + return SKIP_FIRST_RUN; } diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc index 077a1cf..fbd92bc 100644 --- a/chrome/browser/first_run/first_run_win.cc +++ b/chrome/browser/first_run/first_run_win.cc @@ -4,6 +4,7 @@ #include "chrome/browser/first_run/first_run.h" +#include <shellapi.h> #include <shlobj.h> #include <windows.h> @@ -15,6 +16,7 @@ #include "base/string_split.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" +#include "base/win/metro.h" #include "base/win/object_watcher.h" #include "base/win/windows_version.h" #include "chrome/browser/browser_process.h" @@ -52,11 +54,10 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/layout.h" #include "ui/base/ui_base_switches.h" +#include "ui/base/win/shell.h" namespace { -const char kEULASentinelFile[] = "EULA Accepted"; - // Helper class that performs delayed first-run tasks that need more of the // chrome infrastructure to be up and running before they can be attempted. class FirstRunDelayedTasks : public content::NotificationObserver { @@ -144,53 +145,61 @@ void PlatformSetup(Profile* profile) { CreateChromeQuickLaunchShortcut(); } -// Launches the setup exe with the given parameter/value on the command-line, -// waits for its termination, returns its exit code in |*ret_code|, and -// returns true if the exit code is valid. -bool LaunchSetupWithParam(const std::string& param, - const FilePath::StringType& value, - int* ret_code) { - FilePath exe_path; - if (!PathService::Get(base::DIR_MODULE, &exe_path)) +// Launches the setup exe with the given parameter/value on the command-line. +// For non-metro Windows, it waits for its termination, returns its exit code +// in |*ret_code|, and returns true if the exit code is valid. +// For metro Windows, it launches setup via ShellExecuteEx and returns in order +// to bounce the user back to the desktop, then returns immediately. +bool LaunchSetupForEula(const FilePath::StringType& value, int* ret_code) { + FilePath exe_dir; + if (!PathService::Get(base::DIR_MODULE, &exe_dir)) return false; - exe_path = exe_path.Append(installer::kInstallerDir); - exe_path = exe_path.Append(installer::kSetupExe); + exe_dir = exe_dir.Append(installer::kInstallerDir); + FilePath exe_path = exe_dir.Append(installer::kSetupExe); base::ProcessHandle ph; - CommandLine cl(exe_path); - cl.AppendSwitchNative(param, value); + + CommandLine cl(CommandLine::NO_PROGRAM); + cl.AppendSwitchNative(installer::switches::kShowEula, value); CommandLine* browser_command_line = CommandLine::ForCurrentProcess(); if (browser_command_line->HasSwitch(switches::kChromeFrame)) { cl.AppendSwitch(switches::kChromeFrame); } - // TODO(evan): should this use options.wait = true? - if (!base::LaunchProcess(cl, base::LaunchOptions(), &ph)) - return false; - DWORD wr = ::WaitForSingleObject(ph, INFINITE); - if (wr != WAIT_OBJECT_0) - return false; - return (TRUE == ::GetExitCodeProcess(ph, reinterpret_cast<DWORD*>(ret_code))); -} - -// Populates |path| with the path to |file| in the sentinel directory. This is -// the application directory for user-level installs, and the default user data -// dir for system-level installs. Returns false on error. -bool GetSentinelFilePath(const char* file, FilePath* path) { - FilePath exe_path; - if (!PathService::Get(base::DIR_EXE, &exe_path)) - return false; - if (InstallUtil::IsPerUserInstall(exe_path.value().c_str())) - *path = exe_path; - else if (!PathService::Get(chrome::DIR_USER_DATA, path)) + if (base::win::IsMetroProcess()) { + cl.AppendSwitch(installer::switches::kShowEulaForMetro); + + // This obscure use of the 'log usage' mask for windows 8 is documented here + // http://go.microsoft.com/fwlink/?LinkID=243079. It causes the desktop + // process to receive focus. Pass SEE_MASK_FLAG_NO_UI to avoid hangs if an + // error occurs since the UI can't be shown from a metro process. + ui::win::OpenAnyViaShell(exe_path.value(), + exe_dir.value(), + cl.GetCommandLineString(), + SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_FLAG_NO_UI); return false; + } else { + base::LaunchOptions launch_options; + launch_options.wait = true; + CommandLine setup_path(exe_path); + setup_path.AppendArguments(cl, false); + + DWORD exit_code = 0; + if (!base::LaunchProcess(setup_path, launch_options, &ph) || + !::GetExitCodeProcess(ph, &exit_code)) { + return false; + } - *path = path->AppendASCII(file); - return true; + *ret_code = exit_code; + return true; + } } bool GetEULASentinelFilePath(FilePath* path) { - return GetSentinelFilePath(kEULASentinelFile, path); + return InstallUtil::GetSentinelFilePath( + installer::kEULASentinelFile, + BrowserDistribution::GetDistribution(), + path); } // Returns true if the EULA is required but has not been accepted by this user. @@ -234,7 +243,10 @@ bool CreateEULASentinel() { return file_util::WriteFile(eula_sentinel, "", 0) != -1; } -void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { +// Shows the EULA dialog if required. Returns true if the EULA is accepted, +// returns false if the EULA has not been accepted, in which case the browser +// should exit. +bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { if (IsEULANotAccepted(install_prefs)) { // Show the post-installation EULA. This is done by setup.exe and the // result determines if we continue or not. We wait here until the user @@ -245,14 +257,14 @@ void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { FilePath inner_html; if (WriteEULAtoTempFile(&inner_html)) { int retcode = 0; - if (!LaunchSetupWithParam(installer::switches::kShowEula, - inner_html.value(), &retcode) || + if (!LaunchSetupForEula(inner_html.value(), &retcode) || (retcode != installer::EULA_ACCEPTED && retcode != installer::EULA_ACCEPTED_OPT_IN)) { - LOG(WARNING) << "EULA rejected. Fast exit."; - ::ExitProcess(1); + LOG(WARNING) << "EULA flow requires fast exit."; + return false; } CreateEULASentinel(); + if (retcode == installer::EULA_ACCEPTED) { VLOG(1) << "EULA : no collection"; GoogleUpdateSettings::SetCollectStatsConsent(false); @@ -262,6 +274,7 @@ void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { } } } + return true; } // Installs a task to do an extensions update check once the extensions system @@ -498,7 +511,10 @@ bool ImportSettings(Profile* profile, } bool GetFirstRunSentinelFilePath(FilePath* path) { - return GetSentinelFilePath(kSentinelFile, path); + return InstallUtil::GetSentinelFilePath( + kSentinelFile, + BrowserDistribution::GetDistribution(), + path); } void SetImportPreferencesAndLaunchImport( @@ -590,23 +606,26 @@ FilePath MasterPrefsPath() { return master_prefs.AppendASCII(installer::kDefaultMasterPrefs); } -bool ProcessMasterPreferences(const FilePath& user_data_dir, - MasterPrefs* out_prefs) { +ProcessMasterPreferencesResult ProcessMasterPreferences( + const FilePath& user_data_dir, + MasterPrefs* out_prefs) { DCHECK(!user_data_dir.empty()); FilePath master_prefs_path; scoped_ptr<installer::MasterPreferences> install_prefs(internal::LoadMasterPrefs(&master_prefs_path)); if (!install_prefs.get()) - return true; + return SHOW_FIRST_RUN; out_prefs->new_tabs = install_prefs->GetFirstRunTabs(); internal::SetRLZPref(out_prefs, install_prefs.get()); - ShowPostInstallEULAIfNeeded(install_prefs.get()); + + if (!ShowPostInstallEULAIfNeeded(install_prefs.get())) + return EULA_EXIT_NOW; if (!internal::CopyPrefFile(user_data_dir, master_prefs_path)) - return true; + return SHOW_FIRST_RUN; DoDelayedInstallExtensionsIfNeeded(install_prefs.get()); @@ -618,19 +637,19 @@ bool ProcessMasterPreferences(const FilePath& user_data_dir, // Note we are skipping all other master preferences if skip-first-run-ui // is *not* specified. (That is, we continue only if skipping first run ui.) if (!internal::SkipFirstRunUI(install_prefs.get())) - return true; + return SHOW_FIRST_RUN; // We need to be able to create the first run sentinel or else we cannot // proceed because ImportSettings will launch the importer process which // would end up here if the sentinel is not present. if (!CreateSentinel()) - return false; + return SKIP_FIRST_RUN; internal::SetShowWelcomePagePrefIfNeeded(install_prefs.get()); internal::SetImportPreferencesAndLaunchImport(out_prefs, install_prefs.get()); internal::SetDefaultBrowser(install_prefs.get()); - return false; + return SKIP_FIRST_RUN; } } // namespace first_run diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc index 54731ca..a8c3b26 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc @@ -23,6 +23,7 @@ #include "chrome/browser/ui/simple_message_box.h" #include "chrome/common/chrome_constants.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/install_util.h" #include "chrome/installer/util/shell_util.h" #include "chrome/installer/util/wmi.h" #include "content/public/common/result_codes.h" @@ -133,7 +134,8 @@ bool ActivateMetroChrome() { return false; } string16 app_id = ShellUtil::GetBrowserModelId( - BrowserDistribution::GetDistribution(), chrome_exe.value()); + BrowserDistribution::GetDistribution(), + InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())); if (app_id.empty()) { NOTREACHED() << "Failed to get chrome app user model id."; return false; diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index 27b9212..34e8d3e 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc @@ -293,7 +293,8 @@ bool GetExpectedAppId(const FilePath& chrome_exe, command_line.GetSwitchValueASCII(switches::kAppId))); } else { BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - app_name = ShellUtil::GetBrowserModelId(dist, chrome_exe.value()); + app_name = ShellUtil::GetBrowserModelId( + dist, InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())); } expected_app_id->assign( @@ -558,7 +559,9 @@ string16 ShellIntegration::GetChromiumModelIdForProfile( return dist->GetBaseAppId(); } return GetAppModelIdForProfile( - ShellUtil::GetBrowserModelId(dist, chrome_exe.value()), profile_path); + ShellUtil::GetBrowserModelId( + dist, InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())), + profile_path); } string16 ShellIntegration::GetChromiumIconPath() { |