shell_integration.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/shell_integration.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/file_util.h"
10#include "base/path_service.h"
11#include "base/prefs/pref_service.h"
12#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/threading/thread_restrictions.h"
15#include "chrome/browser/policy/policy_path_parser.h"
16#include "chrome/common/chrome_paths.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/pref_names.h"
19#include "content/public/browser/browser_thread.h"
20
21#if defined(OS_CHROMEOS)
22#include "chromeos/chromeos_switches.h"
23#endif
24
25#if !defined(OS_WIN)
26#include "chrome/common/chrome_version_info.h"
27#include "grit/chromium_strings.h"
28#include "ui/base/l10n/l10n_util.h"
29#endif
30
31using content::BrowserThread;
32
33ShellIntegration::DefaultWebClientSetPermission
34    ShellIntegration::CanSetAsDefaultProtocolClient() {
35  // Allowed as long as the browser can become the operating system default
36  // browser.
37  return CanSetAsDefaultBrowser();
38}
39
40ShellIntegration::ShortcutInfo::ShortcutInfo()
41    : is_platform_app(false) {
42}
43
44ShellIntegration::ShortcutInfo::~ShortcutInfo() {}
45
46ShellIntegration::ShortcutLocations::ShortcutLocations()
47    : on_desktop(false),
48      applications_menu_location(APP_MENU_LOCATION_NONE),
49      in_quick_launch_bar(false)
50#if defined(OS_POSIX)
51      , hidden(false)
52#endif
53      {
54}
55
56static const struct ShellIntegration::AppModeInfo* gAppModeInfo = NULL;
57
58// static
59void ShellIntegration::SetAppModeInfo(const struct AppModeInfo* info) {
60  gAppModeInfo = info;
61}
62
63// static
64const struct ShellIntegration::AppModeInfo* ShellIntegration::AppModeInfo() {
65  return gAppModeInfo;
66}
67
68// static
69bool ShellIntegration::IsRunningInAppMode() {
70  return gAppModeInfo != NULL;
71}
72
73// static
74CommandLine ShellIntegration::CommandLineArgsForLauncher(
75    const GURL& url,
76    const std::string& extension_app_id,
77    const base::FilePath& profile_path) {
78  base::ThreadRestrictions::AssertIOAllowed();
79  CommandLine new_cmd_line(CommandLine::NO_PROGRAM);
80
81  AppendProfileArgs(
82      extension_app_id.empty() ? base::FilePath() : profile_path,
83      &new_cmd_line);
84
85  // If |extension_app_id| is present, we use the kAppId switch rather than
86  // the kApp switch (the launch url will be read from the extension app
87  // during launch.
88  if (!extension_app_id.empty()) {
89    new_cmd_line.AppendSwitchASCII(switches::kAppId, extension_app_id);
90  } else {
91    // Use '--app=url' instead of just 'url' to launch the browser with minimal
92    // chrome.
93    // Note: Do not change this flag!  Old Gears shortcuts will break if you do!
94    new_cmd_line.AppendSwitchASCII(switches::kApp, url.spec());
95  }
96  return new_cmd_line;
97}
98
99// static
100void ShellIntegration::AppendProfileArgs(
101    const base::FilePath& profile_path,
102    CommandLine* command_line) {
103  DCHECK(command_line);
104  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
105
106  // Use the same UserDataDir for new launches that we currently have set.
107  base::FilePath user_data_dir =
108      cmd_line.GetSwitchValuePath(switches::kUserDataDir);
109#if defined(OS_MACOSX) || defined(OS_WIN)
110  policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
111#endif
112  if (!user_data_dir.empty()) {
113    // Make sure user_data_dir is an absolute path.
114    user_data_dir = base::MakeAbsoluteFilePath(user_data_dir);
115    if (!user_data_dir.empty() && base::PathExists(user_data_dir))
116      command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
117  }
118
119#if defined(OS_CHROMEOS)
120  base::FilePath profile = cmd_line.GetSwitchValuePath(
121      chromeos::switches::kLoginProfile);
122  if (!profile.empty())
123    command_line->AppendSwitchPath(chromeos::switches::kLoginProfile, profile);
124#else
125  if (!profile_path.empty())
126    command_line->AppendSwitchPath(switches::kProfileDirectory,
127                                   profile_path.BaseName());
128#endif
129}
130
131#if !defined(OS_WIN)
132
133base::string16 ShellIntegration::GetAppShortcutsSubdirName() {
134  if (chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_CANARY)
135    return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY);
136  return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME);
137}
138
139// static
140bool ShellIntegration::SetAsDefaultBrowserInteractive() {
141  return false;
142}
143
144// static
145bool ShellIntegration::SetAsDefaultProtocolClientInteractive(
146    const std::string& protocol) {
147  return false;
148}
149#endif
150
151bool ShellIntegration::DefaultWebClientObserver::IsOwnedByWorker() {
152  return false;
153}
154
155bool ShellIntegration::DefaultWebClientObserver::
156    IsInteractiveSetDefaultPermitted() {
157  return false;
158}
159
160///////////////////////////////////////////////////////////////////////////////
161// ShellIntegration::DefaultWebClientWorker
162//
163
164ShellIntegration::DefaultWebClientWorker::DefaultWebClientWorker(
165    DefaultWebClientObserver* observer)
166    : observer_(observer) {
167}
168
169void ShellIntegration::DefaultWebClientWorker::StartCheckIsDefault() {
170  if (observer_) {
171    observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
172    BrowserThread::PostTask(
173        BrowserThread::FILE, FROM_HERE,
174        base::Bind(
175            &DefaultWebClientWorker::ExecuteCheckIsDefault, this));
176  }
177}
178
179void ShellIntegration::DefaultWebClientWorker::StartSetAsDefault() {
180  bool interactive_permitted = false;
181  if (observer_) {
182    observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
183    interactive_permitted = observer_->IsInteractiveSetDefaultPermitted();
184  }
185  BrowserThread::PostTask(
186      BrowserThread::FILE, FROM_HERE,
187      base::Bind(&DefaultWebClientWorker::ExecuteSetAsDefault, this,
188                 interactive_permitted));
189}
190
191void ShellIntegration::DefaultWebClientWorker::ObserverDestroyed() {
192  // Our associated view has gone away, so we shouldn't call back to it if
193  // our worker thread returns after the view is dead.
194  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
195  observer_ = NULL;
196}
197
198///////////////////////////////////////////////////////////////////////////////
199// DefaultWebClientWorker, private:
200
201void ShellIntegration::DefaultWebClientWorker::ExecuteCheckIsDefault() {
202  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
203  DefaultWebClientState state = CheckIsDefault();
204  BrowserThread::PostTask(
205      BrowserThread::UI, FROM_HERE,
206      base::Bind(
207          &DefaultWebClientWorker::CompleteCheckIsDefault, this, state));
208}
209
210void ShellIntegration::DefaultWebClientWorker::CompleteCheckIsDefault(
211    DefaultWebClientState state) {
212  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213  UpdateUI(state);
214  // The worker has finished everything it needs to do, so free the observer
215  // if we own it.
216  if (observer_ && observer_->IsOwnedByWorker()) {
217    delete observer_;
218    observer_ = NULL;
219  }
220}
221
222void ShellIntegration::DefaultWebClientWorker::ExecuteSetAsDefault(
223    bool interactive_permitted) {
224  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
225
226  bool result = SetAsDefault(interactive_permitted);
227  BrowserThread::PostTask(
228      BrowserThread::UI, FROM_HERE,
229      base::Bind(&DefaultWebClientWorker::CompleteSetAsDefault, this, result));
230}
231
232void ShellIntegration::DefaultWebClientWorker::CompleteSetAsDefault(
233    bool succeeded) {
234  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235  // First tell the observer what the SetAsDefault call has returned.
236  if (observer_)
237    observer_->OnSetAsDefaultConcluded(succeeded);
238  // Set as default completed, check again to make sure it stuck...
239  StartCheckIsDefault();
240}
241
242void ShellIntegration::DefaultWebClientWorker::UpdateUI(
243    DefaultWebClientState state) {
244  if (observer_) {
245    switch (state) {
246      case NOT_DEFAULT:
247        observer_->SetDefaultWebClientUIState(STATE_NOT_DEFAULT);
248        break;
249      case IS_DEFAULT:
250        observer_->SetDefaultWebClientUIState(STATE_IS_DEFAULT);
251        break;
252      case UNKNOWN_DEFAULT:
253        observer_->SetDefaultWebClientUIState(STATE_UNKNOWN);
254        break;
255      default:
256        break;
257    }
258  }
259}
260
261///////////////////////////////////////////////////////////////////////////////
262// ShellIntegration::DefaultBrowserWorker
263//
264
265ShellIntegration::DefaultBrowserWorker::DefaultBrowserWorker(
266    DefaultWebClientObserver* observer)
267    : DefaultWebClientWorker(observer) {
268}
269
270///////////////////////////////////////////////////////////////////////////////
271// DefaultBrowserWorker, private:
272
273ShellIntegration::DefaultWebClientState
274ShellIntegration::DefaultBrowserWorker::CheckIsDefault() {
275  return ShellIntegration::GetDefaultBrowser();
276}
277
278bool ShellIntegration::DefaultBrowserWorker::SetAsDefault(
279    bool interactive_permitted) {
280  bool result = false;
281  switch (ShellIntegration::CanSetAsDefaultBrowser()) {
282    case ShellIntegration::SET_DEFAULT_UNATTENDED:
283      result = ShellIntegration::SetAsDefaultBrowser();
284      break;
285    case ShellIntegration::SET_DEFAULT_INTERACTIVE:
286      if (interactive_permitted)
287        result = ShellIntegration::SetAsDefaultBrowserInteractive();
288      break;
289    default:
290      NOTREACHED();
291  }
292
293  return result;
294}
295
296///////////////////////////////////////////////////////////////////////////////
297// ShellIntegration::DefaultProtocolClientWorker
298//
299
300ShellIntegration::DefaultProtocolClientWorker::DefaultProtocolClientWorker(
301    DefaultWebClientObserver* observer, const std::string& protocol)
302    : DefaultWebClientWorker(observer),
303      protocol_(protocol) {
304}
305
306///////////////////////////////////////////////////////////////////////////////
307// DefaultProtocolClientWorker, private:
308
309ShellIntegration::DefaultWebClientState
310ShellIntegration::DefaultProtocolClientWorker::CheckIsDefault() {
311  return ShellIntegration::IsDefaultProtocolClient(protocol_);
312}
313
314bool ShellIntegration::DefaultProtocolClientWorker::SetAsDefault(
315    bool interactive_permitted) {
316  bool result = false;
317  switch (ShellIntegration::CanSetAsDefaultProtocolClient()) {
318    case ShellIntegration::SET_DEFAULT_NOT_ALLOWED:
319      result = false;
320      break;
321    case ShellIntegration::SET_DEFAULT_UNATTENDED:
322      result = ShellIntegration::SetAsDefaultProtocolClient(protocol_);
323      break;
324    case ShellIntegration::SET_DEFAULT_INTERACTIVE:
325      if (interactive_permitted) {
326        result = ShellIntegration::SetAsDefaultProtocolClientInteractive(
327            protocol_);
328      }
329      break;
330  }
331
332  return result;
333}
334