blob: 2946e4588a40a885a9004a028a9d71e7d8d17cf2 [file] [log] [blame]
[email protected]5a20b192012-03-01 06:01:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]4a0765a2009-05-08 23:12:255#include "chrome/browser/shell_integration.h"
6
[email protected]c5efb952011-11-01 01:28:367#include "base/bind.h"
[email protected]28375ae2010-02-05 04:45:508#include "base/command_line.h"
thestig18dfb7a52014-08-26 10:44:049#include "base/files/file_util.h"
asvitkineaa060312016-09-01 22:44:1310#include "base/metrics/histogram_macros.h"
[email protected]24a555b62013-06-10 22:01:1711#include "base/strings/string_util.h"
pmonette9c1457f2015-11-19 20:29:3112#include "base/strings/stringprintf.h"
[email protected]e309f312013-06-07 21:50:0813#include "base/strings/utf_string_conversions.h"
pmonetteb18379f2017-06-01 01:18:4414#include "base/task_scheduler/post_task.h"
Robert Liao9a8680d2017-07-17 19:58:3215#include "base/task_scheduler/task_traits.h"
[email protected]124901f52013-03-27 14:42:1016#include "base/threading/thread_restrictions.h"
avi664c07b2015-12-26 02:18:3117#include "build/build_config.h"
[email protected]ba26a442013-02-20 15:32:5518#include "chrome/browser/policy/policy_path_parser.h"
[email protected]b96aa932009-08-12 21:34:4919#include "chrome/common/chrome_paths.h"
[email protected]28375ae2010-02-05 04:45:5020#include "chrome/common/chrome_switches.h"
brettwb1fc1b82016-02-02 00:19:0821#include "components/prefs/pref_service.h"
sdefresne9fb67692015-08-03 18:48:2222#include "components/version_info/version_info.h"
[email protected]c38831a12011-10-28 12:44:4923#include "content/public/browser/browser_thread.h"
initial.commit09911bf2008-07-26 23:55:2924
[email protected]931d1042013-04-05 17:50:4425#if defined(OS_CHROMEOS)
26#include "chromeos/chromeos_switches.h"
27#endif
28
pmonette32a5cfb42016-04-11 22:04:4429#if defined(OS_WIN)
30#include "base/win/windows_version.h"
31#include "chrome/browser/shell_integration_win.h"
pmonette0c40087a2016-04-21 00:05:1632#include "chrome/installer/util/shell_util.h"
pmonette32a5cfb42016-04-11 22:04:4433#endif
34
[email protected]2f5bc322013-12-04 08:58:1535#if !defined(OS_WIN)
sdefresne9fb67692015-08-03 18:48:2236#include "chrome/common/channel_info.h"
[email protected]af39f002014-08-22 10:18:1837#include "chrome/grit/chromium_strings.h"
[email protected]2f5bc322013-12-04 08:58:1538#include "ui/base/l10n/l10n_util.h"
39#endif
40
[email protected]631bb742011-11-02 11:29:3941using content::BrowserThread;
42
pmonette9fa59e882016-02-10 00:12:1943namespace shell_integration {
44
pmonette034a03d92015-10-02 21:04:2745namespace {
46
pmonette9fa59e882016-02-10 00:12:1947const struct AppModeInfo* gAppModeInfo = nullptr;
pmonette034a03d92015-10-02 21:04:2748
49} // namespace
50
pmonette32a5cfb42016-04-11 22:04:4451bool CanSetAsDefaultBrowser() {
52 return GetDefaultWebClientSetPermission() != SET_DEFAULT_NOT_ALLOWED;
[email protected]a01481b2011-07-15 04:30:0253}
54
pmonette034a03d92015-10-02 21:04:2755#if !defined(OS_WIN)
pmonette9fa59e882016-02-10 00:12:1956bool IsElevationNeededForSettingDefaultProtocolClient() {
pmonette034a03d92015-10-02 21:04:2757 return false;
58}
59#endif // !defined(OS_WIN)
[email protected]9561bc912012-03-07 02:41:1660
pmonette9fa59e882016-02-10 00:12:1961void SetAppModeInfo(const struct AppModeInfo* info) {
[email protected]9561bc912012-03-07 02:41:1662 gAppModeInfo = info;
63}
64
pmonette9fa59e882016-02-10 00:12:1965const struct AppModeInfo* AppModeInfo() {
[email protected]9561bc912012-03-07 02:41:1666 return gAppModeInfo;
67}
68
pmonette9fa59e882016-02-10 00:12:1969bool IsRunningInAppMode() {
[email protected]9561bc912012-03-07 02:41:1670 return gAppModeInfo != NULL;
71}
72
pmonette9fa59e882016-02-10 00:12:1973base::CommandLine CommandLineArgsForLauncher(
[email protected]2f1c09d2011-01-14 14:58:1474 const GURL& url,
[email protected]5c93a0c12012-05-02 19:45:2475 const std::string& extension_app_id,
[email protected]650b2d52013-02-10 03:41:4576 const base::FilePath& profile_path) {
[email protected]124901f52013-03-27 14:42:1077 base::ThreadRestrictions::AssertIOAllowed();
avi556c05022014-12-22 23:31:4378 base::CommandLine new_cmd_line(base::CommandLine::NO_PROGRAM);
[email protected]28375ae2010-02-05 04:45:5079
[email protected]fb06aea82014-02-26 15:48:4780 AppendProfileArgs(
81 extension_app_id.empty() ? base::FilePath() : profile_path,
82 &new_cmd_line);
[email protected]28375ae2010-02-05 04:45:5083
84 // If |extension_app_id| is present, we use the kAppId switch rather than
85 // the kApp switch (the launch url will be read from the extension app
86 // during launch.
[email protected]ec5b50d2010-10-09 16:35:1887 if (!extension_app_id.empty()) {
[email protected]b10392932011-03-08 21:28:1488 new_cmd_line.AppendSwitchASCII(switches::kAppId, extension_app_id);
[email protected]64048bd2010-03-08 23:28:5889 } else {
[email protected]28375ae2010-02-05 04:45:5090 // Use '--app=url' instead of just 'url' to launch the browser with minimal
91 // chrome.
92 // Note: Do not change this flag! Old Gears shortcuts will break if you do!
[email protected]b10392932011-03-08 21:28:1493 new_cmd_line.AppendSwitchASCII(switches::kApp, url.spec());
[email protected]28375ae2010-02-05 04:45:5094 }
[email protected]b10392932011-03-08 21:28:1495 return new_cmd_line;
[email protected]28375ae2010-02-05 04:45:5096}
97
pmonette9fa59e882016-02-10 00:12:1998void AppendProfileArgs(const base::FilePath& profile_path,
99 base::CommandLine* command_line) {
[email protected]fb06aea82014-02-26 15:48:47100 DCHECK(command_line);
avi556c05022014-12-22 23:31:43101 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
[email protected]fb06aea82014-02-26 15:48:47102
103 // Use the same UserDataDir for new launches that we currently have set.
104 base::FilePath user_data_dir =
105 cmd_line.GetSwitchValuePath(switches::kUserDataDir);
106#if defined(OS_MACOSX) || defined(OS_WIN)
107 policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
108#endif
109 if (!user_data_dir.empty()) {
110 // Make sure user_data_dir is an absolute path.
111 user_data_dir = base::MakeAbsoluteFilePath(user_data_dir);
112 if (!user_data_dir.empty() && base::PathExists(user_data_dir))
113 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
114 }
115
116#if defined(OS_CHROMEOS)
117 base::FilePath profile = cmd_line.GetSwitchValuePath(
118 chromeos::switches::kLoginProfile);
119 if (!profile.empty())
120 command_line->AppendSwitchPath(chromeos::switches::kLoginProfile, profile);
121#else
122 if (!profile_path.empty())
123 command_line->AppendSwitchPath(switches::kProfileDirectory,
124 profile_path.BaseName());
125#endif
126}
127
[email protected]bd046bd42012-06-08 05:07:32128#if !defined(OS_WIN)
pmonette9fa59e882016-02-10 00:12:19129base::string16 GetAppShortcutsSubdirName() {
sdefresne9fb67692015-08-03 18:48:22130 if (chrome::GetChannel() == version_info::Channel::CANARY)
[email protected]2f5bc322013-12-04 08:58:15131 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY);
132 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME);
133}
pmonette868ca642015-09-02 14:34:02134#endif // !defined(OS_WIN)
[email protected]bd046bd42012-06-08 05:07:32135
pmonette034a03d92015-10-02 21:04:27136///////////////////////////////////////////////////////////////////////////////
pmonette9fa59e882016-02-10 00:12:19137// DefaultWebClientWorker
[email protected]d24c4012009-07-28 01:57:31138//
initial.commit09911bf2008-07-26 23:55:29139
pmonette9fa59e882016-02-10 00:12:19140void DefaultWebClientWorker::StartCheckIsDefault() {
pmonetteb18379f2017-06-01 01:18:44141 GetTaskRunner()->PostTask(
142 FROM_HERE,
pmonette60a702c2016-03-22 22:59:40143 base::Bind(&DefaultWebClientWorker::CheckIsDefault, this, false));
[email protected]4468a5b2011-05-26 07:48:02144}
145
pmonette9fa59e882016-02-10 00:12:19146void DefaultWebClientWorker::StartSetAsDefault() {
pmonetteb18379f2017-06-01 01:18:44147 GetTaskRunner()->PostTask(
148 FROM_HERE, base::Bind(&DefaultWebClientWorker::SetAsDefault, this));
initial.commit09911bf2008-07-26 23:55:29149}
150
[email protected]d24c4012009-07-28 01:57:31151///////////////////////////////////////////////////////////////////////////////
pmonette5207d8952016-03-22 15:53:08152// DefaultWebClientWorker, protected:
[email protected]d24c4012009-07-28 01:57:31153
pmonette5207d8952016-03-22 15:53:08154DefaultWebClientWorker::DefaultWebClientWorker(
155 const DefaultWebClientWorkerCallback& callback,
156 const char* worker_name)
157 : callback_(callback), worker_name_(worker_name) {}
158
159DefaultWebClientWorker::~DefaultWebClientWorker() = default;
[email protected]d24c4012009-07-28 01:57:31160
pmonette9fa59e882016-02-10 00:12:19161void DefaultWebClientWorker::OnCheckIsDefaultComplete(
pmonette60a702c2016-03-22 22:59:40162 DefaultWebClientState state,
163 bool is_following_set_as_default) {
thestig00844cea2015-09-08 21:44:52164 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]264f74d12009-09-04 23:39:58165 UpdateUI(state);
pmonette9c1457f2015-11-19 20:29:31166
pmonette60a702c2016-03-22 22:59:40167 if (is_following_set_as_default)
168 ReportSetDefaultResult(state);
pmonette5207d8952016-03-22 15:53:08169}
pmonettef89ac7c72015-10-06 03:22:01170
pmonette5207d8952016-03-22 15:53:08171///////////////////////////////////////////////////////////////////////////////
172// DefaultWebClientWorker, private:
pmonettef89ac7c72015-10-06 03:22:01173
pmonetteb18379f2017-06-01 01:18:44174// static
175scoped_refptr<base::SequencedTaskRunner>
176DefaultWebClientWorker::GetTaskRunner() {
177 DCHECK_CURRENTLY_ON(BrowserThread::UI);
178
179 // TODO(pmonette): The better way to make sure all instances of
180 // DefaultWebClient share a SequencedTaskRunner is to make the worker a
181 // singleton.
182 static scoped_refptr<base::SequencedTaskRunner>* task_runner = nullptr;
183
Robert Liao9a8680d2017-07-17 19:58:32184 constexpr base::TaskTraits traits = {base::MayBlock()};
185
pmonetteb18379f2017-06-01 01:18:44186 if (!task_runner) {
Robert Liao9a8680d2017-07-17 19:58:32187#if defined(OS_WIN)
188 // Shell integration calls like shell_integration::GetDefaultBrowser require
189 // the thread to have COM initialized.
pmonetteb18379f2017-06-01 01:18:44190 task_runner = new scoped_refptr<base::SequencedTaskRunner>(
Robert Liao9a8680d2017-07-17 19:58:32191 base::CreateCOMSTATaskRunnerWithTraits(traits));
192#else
193 task_runner = new scoped_refptr<base::SequencedTaskRunner>(
194 base::CreateSequencedTaskRunnerWithTraits(traits));
195#endif
pmonetteb18379f2017-06-01 01:18:44196 }
197
198 return *task_runner;
199}
200
pmonette60a702c2016-03-22 22:59:40201void DefaultWebClientWorker::CheckIsDefault(bool is_following_set_as_default) {
pmonetteb18379f2017-06-01 01:18:44202 base::ThreadRestrictions::AssertIOAllowed();
203
pmonette5207d8952016-03-22 15:53:08204 DefaultWebClientState state = CheckIsDefaultImpl();
205 BrowserThread::PostTask(
206 BrowserThread::UI, FROM_HERE,
pmonette60a702c2016-03-22 22:59:40207 base::Bind(&DefaultBrowserWorker::OnCheckIsDefaultComplete, this, state,
208 is_following_set_as_default));
pmonette5207d8952016-03-22 15:53:08209}
210
211void DefaultWebClientWorker::SetAsDefault() {
pmonetteb18379f2017-06-01 01:18:44212 base::ThreadRestrictions::AssertIOAllowed();
pmonette32a5cfb42016-04-11 22:04:44213
214 // SetAsDefaultImpl will make sure the callback is executed exactly once.
215 SetAsDefaultImpl(
216 base::Bind(&DefaultWebClientWorker::CheckIsDefault, this, true));
[email protected]d24c4012009-07-28 01:57:31217}
218
pmonette60a702c2016-03-22 22:59:40219void DefaultWebClientWorker::ReportSetDefaultResult(
220 DefaultWebClientState state) {
pmonette9c1457f2015-11-19 20:29:31221 base::LinearHistogram::FactoryGet(
pmonette60a702c2016-03-22 22:59:40222 base::StringPrintf("%s.SetDefaultResult2", worker_name_), 1,
223 DefaultWebClientState::NUM_DEFAULT_STATES,
224 DefaultWebClientState::NUM_DEFAULT_STATES + 1,
pmonette9c1457f2015-11-19 20:29:31225 base::HistogramBase::kUmaTargetedHistogramFlag)
pmonette60a702c2016-03-22 22:59:40226 ->Add(state);
pmonettef89ac7c72015-10-06 03:22:01227}
228
pmonette9fa59e882016-02-10 00:12:19229void DefaultWebClientWorker::UpdateUI(DefaultWebClientState state) {
pmonettef9461d1a2016-03-08 18:13:47230 if (!callback_.is_null()) {
231 switch (state) {
232 case NOT_DEFAULT:
pmonetteb9204142016-03-08 20:02:44233 callback_.Run(NOT_DEFAULT);
pmonettef9461d1a2016-03-08 18:13:47234 break;
235 case IS_DEFAULT:
pmonetteb9204142016-03-08 20:02:44236 callback_.Run(IS_DEFAULT);
pmonettef9461d1a2016-03-08 18:13:47237 break;
238 case UNKNOWN_DEFAULT:
pmonetteb9204142016-03-08 20:02:44239 callback_.Run(UNKNOWN_DEFAULT);
pmonettef9461d1a2016-03-08 18:13:47240 break;
241 case NUM_DEFAULT_STATES:
pmonetteb9204142016-03-08 20:02:44242 NOTREACHED();
pmonettef9461d1a2016-03-08 18:13:47243 break;
244 }
[email protected]d24c4012009-07-28 01:57:31245 }
initial.commit09911bf2008-07-26 23:55:29246}
[email protected]4468a5b2011-05-26 07:48:02247
248///////////////////////////////////////////////////////////////////////////////
pmonette9fa59e882016-02-10 00:12:19249// DefaultBrowserWorker
[email protected]4468a5b2011-05-26 07:48:02250//
251
pmonette586ab5b32016-03-07 19:50:37252DefaultBrowserWorker::DefaultBrowserWorker(
253 const DefaultWebClientWorkerCallback& callback)
pmonette5207d8952016-03-22 15:53:08254 : DefaultWebClientWorker(callback, "DefaultBrowser") {}
pmonettef89ac7c72015-10-06 03:22:01255
[email protected]4468a5b2011-05-26 07:48:02256///////////////////////////////////////////////////////////////////////////////
257// DefaultBrowserWorker, private:
258
pmonette5207d8952016-03-22 15:53:08259DefaultBrowserWorker::~DefaultBrowserWorker() = default;
260
261DefaultWebClientState DefaultBrowserWorker::CheckIsDefaultImpl() {
262 return GetDefaultBrowser();
[email protected]4468a5b2011-05-26 07:48:02263}
264
pmonette32a5cfb42016-04-11 22:04:44265void DefaultBrowserWorker::SetAsDefaultImpl(
266 const base::Closure& on_finished_callback) {
267 switch (GetDefaultWebClientSetPermission()) {
pmonettef89ac7c72015-10-06 03:22:01268 case SET_DEFAULT_NOT_ALLOWED:
[email protected]bd046bd42012-06-08 05:07:32269 NOTREACHED();
pmonettef89ac7c72015-10-06 03:22:01270 break;
271 case SET_DEFAULT_UNATTENDED:
pmonette60a702c2016-03-22 22:59:40272 SetAsDefaultBrowser();
pmonettef89ac7c72015-10-06 03:22:01273 break;
274 case SET_DEFAULT_INTERACTIVE:
pmonette32a5cfb42016-04-11 22:04:44275#if defined(OS_WIN)
276 if (interactive_permitted_) {
pmonette0c40087a2016-04-21 00:05:16277 switch (ShellUtil::GetInteractiveSetDefaultMode()) {
278 case ShellUtil::INTENT_PICKER:
279 win::SetAsDefaultBrowserUsingIntentPicker();
280 break;
281 case ShellUtil::SYSTEM_SETTINGS:
282 win::SetAsDefaultBrowserUsingSystemSettings(on_finished_callback);
283 // Early return because the function above takes care of calling
284 // |on_finished_callback|.
285 return;
pmonette32a5cfb42016-04-11 22:04:44286 }
287 }
288#endif // defined(OS_WIN)
pmonettef89ac7c72015-10-06 03:22:01289 break;
[email protected]bd046bd42012-06-08 05:07:32290 }
pmonette32a5cfb42016-04-11 22:04:44291 on_finished_callback.Run();
pmonette9c1457f2015-11-19 20:29:31292}
293
[email protected]4468a5b2011-05-26 07:48:02294///////////////////////////////////////////////////////////////////////////////
pmonette9fa59e882016-02-10 00:12:19295// DefaultProtocolClientWorker
[email protected]4468a5b2011-05-26 07:48:02296//
297
pmonette9fa59e882016-02-10 00:12:19298DefaultProtocolClientWorker::DefaultProtocolClientWorker(
pmonette586ab5b32016-03-07 19:50:37299 const DefaultWebClientWorkerCallback& callback,
300 const std::string& protocol)
pmonette5207d8952016-03-22 15:53:08301 : DefaultWebClientWorker(callback, "DefaultProtocolClient"),
302 protocol_(protocol) {}
303
304///////////////////////////////////////////////////////////////////////////////
305// DefaultProtocolClientWorker, protected:
306
307DefaultProtocolClientWorker::~DefaultProtocolClientWorker() = default;
[email protected]4468a5b2011-05-26 07:48:02308
309///////////////////////////////////////////////////////////////////////////////
310// DefaultProtocolClientWorker, private:
311
pmonette5207d8952016-03-22 15:53:08312DefaultWebClientState DefaultProtocolClientWorker::CheckIsDefaultImpl() {
313 return IsDefaultProtocolClient(protocol_);
[email protected]4468a5b2011-05-26 07:48:02314}
315
pmonette32a5cfb42016-04-11 22:04:44316void DefaultProtocolClientWorker::SetAsDefaultImpl(
317 const base::Closure& on_finished_callback) {
318 switch (GetDefaultWebClientSetPermission()) {
pmonettef89ac7c72015-10-06 03:22:01319 case SET_DEFAULT_NOT_ALLOWED:
320 // Not allowed, do nothing.
[email protected]e7f79872013-09-13 01:39:31321 break;
pmonettef89ac7c72015-10-06 03:22:01322 case SET_DEFAULT_UNATTENDED:
pmonette60a702c2016-03-22 22:59:40323 SetAsDefaultProtocolClient(protocol_);
[email protected]ee9d89d2012-09-25 18:21:03324 break;
pmonettef89ac7c72015-10-06 03:22:01325 case SET_DEFAULT_INTERACTIVE:
pmonette32a5cfb42016-04-11 22:04:44326#if defined(OS_WIN)
pmonette0c40087a2016-04-21 00:05:16327 if (interactive_permitted_) {
328 switch (ShellUtil::GetInteractiveSetDefaultMode()) {
329 case ShellUtil::INTENT_PICKER:
330 win::SetAsDefaultProtocolClientUsingIntentPicker(protocol_);
331 break;
332 case ShellUtil::SYSTEM_SETTINGS:
333 win::SetAsDefaultProtocolClientUsingSystemSettings(
334 protocol_, on_finished_callback);
335 // Early return because the function above takes care of calling
336 // |on_finished_callback|.
337 return;
338 }
339 }
pmonette32a5cfb42016-04-11 22:04:44340#endif // defined(OS_WIN)
[email protected]ee9d89d2012-09-25 18:21:03341 break;
[email protected]ee9d89d2012-09-25 18:21:03342 }
pmonette32a5cfb42016-04-11 22:04:44343 on_finished_callback.Run();
pmonette9c1457f2015-11-19 20:29:31344}
pmonette9fa59e882016-02-10 00:12:19345
346} // namespace shell_integration