| Index: chrome/browser/shell_integration_win.cc
|
| diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
|
| index a27448c8c863590a71b8b6a953cb97435862d72d..4089dc47a12765898c4a3413352e26cabed14faf 100644
|
| --- a/chrome/browser/shell_integration_win.cc
|
| +++ b/chrome/browser/shell_integration_win.cc
|
| @@ -14,17 +14,22 @@
|
| #include "base/files/file_enumerator.h"
|
| #include "base/files/file_util.h"
|
| #include "base/message_loop/message_loop.h"
|
| +#include "base/metrics/field_trial.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| #include "base/path_service.h"
|
| +#include "base/process/launch.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "base/timer/timer.h"
|
| #include "base/win/registry.h"
|
| #include "base/win/scoped_comptr.h"
|
| #include "base/win/scoped_propvariant.h"
|
| #include "base/win/shortcut.h"
|
| #include "base/win/windows_version.h"
|
| #include "chrome/browser/policy/policy_path_parser.h"
|
| +#include "chrome/browser/ui/startup/startup_browser_creator.h"
|
| #include "chrome/browser/web_applications/web_app.h"
|
| #include "chrome/common/chrome_constants.h"
|
| #include "chrome/common/chrome_paths_internal.h"
|
| @@ -38,6 +43,7 @@
|
| #include "chrome/installer/util/util_constants.h"
|
| #include "chrome/installer/util/work_item.h"
|
| #include "chrome/installer/util/work_item_list.h"
|
| +#include "components/variations/variations_associated_data.h"
|
| #include "content/public/browser/browser_thread.h"
|
|
|
| using content::BrowserThread;
|
| @@ -46,6 +52,10 @@ namespace {
|
|
|
| const wchar_t kAppListAppNameSuffix[] = L"AppList";
|
|
|
| +const char kAsyncSetAsDefaultExperimentName[] = "AsyncSetAsDefault";
|
| +const char kEnableAsyncSetAsDefault[] = "enable-async-set-as-default";
|
| +const char kDisableAsyncSetAsDefault[] = "disable-async-set-as-default";
|
| +
|
| // Helper function for ShellIntegration::GetAppId to generates profile id
|
| // from profile path. "profile_id" is composed of sanitized basenames of
|
| // user data dir and profile dir joined by a ".".
|
| @@ -240,8 +250,49 @@ ShellIntegration::DefaultWebClientState
|
| }
|
| }
|
|
|
| +// Resets the default browser choice for the current user.
|
| +void ResetDefaultBrowser() {
|
| + static const wchar_t* const kUrlAssociationKeyFormats[] = {
|
| + L"SOFTWARE\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
|
| + L"%ls\\UserChoice",
|
| + L"SOFTWARE\\Microsoft\\Windows\\Roaming\\OpenWith\\UrlAssociations\\"
|
| + L"%ls\\UserChoice"};
|
| + static const wchar_t* const kProtocols[] = {L"http", L"https"};
|
| +
|
| + for (const wchar_t* format : kUrlAssociationKeyFormats) {
|
| + for (const wchar_t* protocol : kProtocols) {
|
| + base::win::RegKey registry_key(
|
| + HKEY_CURRENT_USER, base::StringPrintf(format, protocol).c_str(),
|
| + KEY_SET_VALUE);
|
| + registry_key.DeleteValue(L"Hash");
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Returns true if the AsyncSetAsDefault field trial is activated.
|
| +bool IsAsyncSetAsDefaultEnabled() {
|
| + using base::CommandLine;
|
| +
|
| + // Note: It's important to query the field trial state first, to ensure that
|
| + // UMA reports the correct group.
|
| + const std::string group_name =
|
| + base::FieldTrialList::FindFullName("AsyncSetAsDefault");
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(kDisableAsyncSetAsDefault))
|
| + return false;
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableAsyncSetAsDefault))
|
| + return true;
|
| +
|
| + return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
|
| +}
|
| +
|
| } // namespace
|
|
|
| +// static
|
| +bool ShellIntegration::IsSetAsDefaultAsynchronous() {
|
| + return base::win::GetVersion() >= base::win::VERSION_WIN10 &&
|
| + IsAsyncSetAsDefaultEnabled();
|
| +}
|
| +
|
| bool ShellIntegration::SetAsDefaultBrowser() {
|
| base::FilePath chrome_exe;
|
| if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
|
| @@ -327,11 +378,11 @@ ShellIntegration::DefaultWebClientSetPermission
|
| if (distribution->GetDefaultBrowserControlPolicy() !=
|
| BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL)
|
| return SET_DEFAULT_NOT_ALLOWED;
|
| -
|
| if (ShellUtil::CanMakeChromeDefaultUnattended())
|
| return SET_DEFAULT_UNATTENDED;
|
| - else
|
| - return SET_DEFAULT_INTERACTIVE;
|
| + if (IsSetAsDefaultAsynchronous())
|
| + return SET_DEFAULT_ASYNCHRONOUS;
|
| + return SET_DEFAULT_INTERACTIVE;
|
| }
|
|
|
| bool ShellIntegration::IsElevationNeededForSettingDefaultProtocolClient() {
|
| @@ -419,8 +470,7 @@ base::string16 ShellIntegration::GetChromiumModelIdForProfile(
|
|
|
| base::string16 ShellIntegration::GetAppListAppModelIdForProfile(
|
| const base::FilePath& profile_path) {
|
| - return ShellIntegration::GetAppModelIdForProfile(
|
| - GetAppListAppName(), profile_path);
|
| + return GetAppModelIdForProfile(GetAppListAppName(), profile_path);
|
| }
|
|
|
| void ShellIntegration::MigrateChromiumShortcuts() {
|
| @@ -588,3 +638,76 @@ base::FilePath ShellIntegration::GetStartMenuShortcut(
|
|
|
| return base::FilePath();
|
| }
|
| +
|
| +// static
|
| +bool ShellIntegration::DefaultWebClientWorker::ShouldReportAttemptResults() {
|
| + return base::win::GetVersion() >= base::win::VERSION_WIN10 &&
|
| + IsSetAsDefaultAsynchronous();
|
| +}
|
| +
|
| +bool ShellIntegration::DefaultBrowserWorker::InitializeSetAsDefault() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + if (!IsSetAsDefaultAsynchronous())
|
| + return false;
|
| +
|
| + // On Windows 10+, there is no official way to prompt the user to set a
|
| + // default browser. This is the workaround:
|
| + // 1. Unregister the default browser.
|
| + // 2. Open "How to make Chrome my default browser" link with openwith.exe.
|
| + // 3. Windows will prompt the user with "How would you link to open this?".
|
| + // 4. If Chrome is selected, we intercept the attempt to open the URL and
|
| + // instead call OnSetAsDefaultAttemptComplete(), passing true to indicate
|
| + // success.
|
| + // 5. If Chrome is not selected, the url is opened in the selected browser.
|
| + // After a certain amount of time, we notify the observer that the
|
| + // process failed.
|
| +
|
| + if (!StartupBrowserCreator::SetDefaultBrowserCallback(
|
| + base::Bind(&DefaultBrowserWorker::OnSetAsDefaultAttemptComplete, this,
|
| + AttemptResult::SUCCESS))) {
|
| + // Another worker is currently processing. Note that this will still cause
|
| + // SetAsDefaultBrowserAsynchronous() to be invoked in SetAsDefault() but
|
| + // the other worker will happily intercept the attempt.
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DefaultBrowserWorker::OnSetAsDefaultAttemptComplete, this,
|
| + AttemptResult::OTHER_WORKER));
|
| + return false;
|
| + }
|
| +
|
| + // Start the timer.
|
| + if (!async_timer_)
|
| + async_timer_.reset(new base::OneShotTimer());
|
| + std::string value = variations::GetVariationParamValue(
|
| + kAsyncSetAsDefaultExperimentName, "TimerDuration");
|
| + int seconds = 0;
|
| + if (!value.empty())
|
| + base::StringToInt(value, &seconds);
|
| + if (!seconds)
|
| + seconds = 120; // Default value of 2 minutes.
|
| + async_timer_->Start(
|
| + FROM_HERE, base::TimeDelta::FromSeconds(seconds),
|
| + base::Bind(&DefaultBrowserWorker::OnSetAsDefaultAttemptComplete, this,
|
| + AttemptResult::FAILURE));
|
| + return true;
|
| +}
|
| +
|
| +void ShellIntegration::DefaultBrowserWorker::FinalizeSetAsDefault() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + DCHECK(set_as_default_initialized());
|
| +
|
| + async_timer_.reset();
|
| + StartupBrowserCreator::ClearDefaultBrowserCallback();
|
| +}
|
| +
|
| +// static
|
| +bool ShellIntegration::DefaultBrowserWorker::SetAsDefaultBrowserAsynchronous() {
|
| + DCHECK(IsSetAsDefaultAsynchronous());
|
| +
|
| + ResetDefaultBrowser();
|
| +
|
| + base::CommandLine cmdline(base::FilePath(L"openwith.exe"));
|
| + cmdline.AppendArgNative(StartupBrowserCreator::GetDefaultBrowserUrl());
|
| + return base::LaunchProcess(cmdline, base::LaunchOptions()).IsValid();
|
| +}
|
|
|