| Index: chrome/browser/shell_integration_win.cc
|
| diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
|
| index 07f7b4b9f8e465faaad7240654e82ebedbb91644..1320ef46cd837776a8d8c91e29014c47c32ddf54 100644
|
| --- a/chrome/browser/shell_integration_win.cc
|
| +++ b/chrome/browser/shell_integration_win.cc
|
| @@ -14,7 +14,10 @@
|
| #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"
|
| @@ -25,6 +28,7 @@
|
| #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 +42,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 +51,14 @@ namespace {
|
|
|
| const wchar_t kAppListAppNameSuffix[] = L"AppList";
|
|
|
| +const wchar_t kOpenWithCmdLineFormat[] = L"openwith.exe %ls";
|
| +const wchar_t kSetDefaultBrowserHelpUrl[] =
|
| + L"https://support.google.com/chrome?p=default_browser";
|
| +
|
| +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 +253,56 @@ ShellIntegration::DefaultWebClientState
|
| }
|
| }
|
|
|
| +// Resets the default browser choice for the current user.
|
| +void ResetDefaultBrowser() {
|
| + static const wchar_t* 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* 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_WRITE);
|
| + registry_key.DeleteValue(L"Hash");
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Returns true if the AsyncSetAsDefault field trial is activated.
|
| +bool IsAsyncSetAsDefaultEnabled() {
|
| + using base::CommandLine;
|
| +
|
| + 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();
|
| +}
|
| +
|
| +void ShellIntegration::SetAsDefaultBrowserAsynchronous() {
|
| + DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN10);
|
| +
|
| + ResetDefaultBrowser();
|
| + base::LaunchProcess(
|
| + base::StringPrintf(kOpenWithCmdLineFormat, kSetDefaultBrowserHelpUrl),
|
| + base::LaunchOptions());
|
| +}
|
| +
|
| ShellIntegration::DefaultWebClientSetPermission
|
| ShellIntegration::CanSetAsDefaultBrowser() {
|
| BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
|
| @@ -251,6 +312,8 @@ ShellIntegration::DefaultWebClientSetPermission
|
|
|
| if (ShellUtil::CanMakeChromeDefaultUnattended())
|
| return SET_DEFAULT_UNATTENDED;
|
| + else if (IsSetAsDefaultAsynchronous())
|
| + return SET_DEFAULT_ASYNCHRONOUS;
|
| else
|
| return SET_DEFAULT_INTERACTIVE;
|
| }
|
| @@ -588,3 +651,58 @@ base::FilePath ShellIntegration::GetStartMenuShortcut(
|
|
|
| return base::FilePath();
|
| }
|
| +
|
| +void ShellIntegration::DefaultBrowserWorker::InitializeSetAsDefault() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + if (IsSetAsDefaultAsynchronous()) {
|
| + StartupBrowserCreator::AddUrlFilter(
|
| + GURL(kSetDefaultBrowserHelpUrl),
|
| + base::Bind(&DefaultBrowserWorker::CompleteSetAsDefault, this, true));
|
| +
|
| + // Remember the start time.
|
| + start_time_ = base::TimeTicks::Now();
|
| +
|
| + // Start the timer.
|
| + if (!async_timer_)
|
| + async_timer_.reset(new base::OneShotTimer<DefaultWebClientWorker>());
|
| +
|
| + base::TimeDelta timer_duration = base::TimeDelta::FromMinutes(2);
|
| + std::string value = variations::GetVariationParamValue(
|
| + kAsyncSetAsDefaultExperimentName, "TimerDuration");
|
| + if (!value.empty())
|
| + timer_duration = base::TimeDelta::FromSeconds(std::atoi(value.c_str()));
|
| +
|
| + async_timer_->Start(
|
| + FROM_HERE, timer_duration,
|
| + base::Bind(&DefaultBrowserWorker::CompleteSetAsDefault, this, false));
|
| + }
|
| +}
|
| +
|
| +bool ShellIntegration::DefaultBrowserWorker::UninitializeSetAsDefault(
|
| + bool succeeded) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + if (IsSetAsDefaultAsynchronous()) {
|
| + GURL default_browser_help_url(kSetDefaultBrowserHelpUrl);
|
| + if (!async_timer_) {
|
| + // If the timer isnt set, that means it has already fired and
|
| + // the observer should not be notified again.
|
| + DCHECK(!StartupBrowserCreator::UrlFilterExists(default_browser_help_url));
|
| + return false;
|
| + }
|
| +
|
| + // Record the duration from starting to set as default browser to now.
|
| + UMA_HISTOGRAM_BOOLEAN("AsyncSetAsDefault.Succeeded", succeeded);
|
| + UMA_HISTOGRAM_TIMES("AsyncSetAsDefault.Duration",
|
| + base::TimeTicks::Now() - start_time_);
|
| +
|
| + // Destroy timer.
|
| + async_timer_.reset();
|
| +
|
| + // Remove filter if it exists.
|
| + if (StartupBrowserCreator::UrlFilterExists(default_browser_help_url))
|
| + StartupBrowserCreator::RemoveUrlFilter(default_browser_help_url);
|
| + }
|
| + return true;
|
| +}
|
|
|