web_app.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/web_applications/web_app.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/file_util.h"
10#include "base/i18n/file_util_icu.h"
11#include "base/string_util.h"
12#include "base/threading/thread.h"
13#include "base/utf_string_conversions.h"
14#include "chrome/common/chrome_constants.h"
15#include "chrome/common/chrome_version_info.h"
16#include "chrome/common/extensions/extension.h"
17#include "chrome/common/url_constants.h"
18#include "content/public/browser/browser_thread.h"
19#include "extensions/common/constants.h"
20#include "grit/chromium_strings.h"
21#include "ui/base/l10n/l10n_util.h"
22
23using content::BrowserThread;
24
25namespace {
26
27#if defined(TOOLKIT_VIEWS)
28// Predicator for sorting images from largest to smallest.
29bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
30                  const WebApplicationInfo::IconInfo& right) {
31  return left.width < right.width;
32}
33#endif
34
35void DeleteShortcutsOnFileThread(
36    const ShellIntegration::ShortcutInfo& shortcut_info) {
37  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
38
39  base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
40      shortcut_info.profile_path, shortcut_info.extension_id, GURL());
41  return web_app::internals::DeletePlatformShortcuts(
42      shortcut_data_dir, shortcut_info);
43}
44
45void UpdateShortcutsOnFileThread(
46    const ShellIntegration::ShortcutInfo& shortcut_info) {
47  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
48
49  base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
50      shortcut_info.profile_path, shortcut_info.extension_id, GURL());
51  return web_app::internals::UpdatePlatformShortcuts(
52      shortcut_data_dir, shortcut_info);
53}
54
55}  // namespace
56
57namespace web_app {
58
59// The following string is used to build the directory name for
60// shortcuts to chrome applications (the kind which are installed
61// from a CRX).  Application shortcuts to URLs use the {host}_{path}
62// for the name of this directory.  Hosts can't include an underscore.
63// By starting this string with an underscore, we ensure that there
64// are no naming conflicts.
65static const char* kCrxAppPrefix = "_crx_";
66
67namespace internals {
68
69base::FilePath GetSanitizedFileName(const string16& name) {
70#if defined(OS_WIN)
71  string16 file_name = name;
72#else
73  std::string file_name = UTF16ToUTF8(name);
74#endif
75  file_util::ReplaceIllegalCharactersInPath(&file_name, '_');
76  return base::FilePath(file_name);
77}
78
79}  // namespace internals
80
81base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
82                                      const std::string& extension_id,
83                                      const GURL& url) {
84  DCHECK(!profile_path.empty());
85  base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
86
87  if (!extension_id.empty()) {
88    return app_data_dir.AppendASCII(
89        GenerateApplicationNameFromExtensionId(extension_id));
90  }
91
92  std::string host(url.host());
93  std::string scheme(url.has_scheme() ? url.scheme() : "http");
94  std::string port(url.has_port() ? url.port() : "80");
95  std::string scheme_port(scheme + "_" + port);
96
97#if defined(OS_WIN)
98  base::FilePath::StringType host_path(UTF8ToUTF16(host));
99  base::FilePath::StringType scheme_port_path(UTF8ToUTF16(scheme_port));
100#elif defined(OS_POSIX)
101  base::FilePath::StringType host_path(host);
102  base::FilePath::StringType scheme_port_path(scheme_port);
103#endif
104
105  return app_data_dir.Append(host_path).Append(scheme_port_path);
106}
107
108base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
109                                      const extensions::Extension& extension) {
110  return GetWebAppDataDirectory(
111      profile_path, extension.id(), GURL(extension.launch_web_url()));
112}
113
114std::string GenerateApplicationNameFromInfo(
115    const ShellIntegration::ShortcutInfo& shortcut_info) {
116  if (!shortcut_info.extension_id.empty()) {
117    return web_app::GenerateApplicationNameFromExtensionId(
118        shortcut_info.extension_id);
119  } else {
120    return web_app::GenerateApplicationNameFromURL(
121        shortcut_info.url);
122  }
123}
124
125std::string GenerateApplicationNameFromURL(const GURL& url) {
126  std::string t;
127  t.append(url.host());
128  t.append("_");
129  t.append(url.path());
130  return t;
131}
132
133std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
134  std::string t(web_app::kCrxAppPrefix);
135  t.append(id);
136  return t;
137}
138
139std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
140  std::string prefix(kCrxAppPrefix);
141  if (app_name.substr(0, prefix.length()) != prefix)
142    return std::string();
143  return app_name.substr(prefix.length());
144}
145
146void CreateShortcuts(
147    const ShellIntegration::ShortcutInfo& shortcut_info,
148    const ShellIntegration::ShortcutLocations& creation_locations) {
149  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150
151  BrowserThread::PostTask(
152      BrowserThread::FILE,
153      FROM_HERE,
154      base::Bind(base::IgnoreResult(&CreateShortcutsOnFileThread),
155                 shortcut_info, creation_locations));
156}
157
158void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
159  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160
161  BrowserThread::PostTask(
162      BrowserThread::FILE,
163      FROM_HERE,
164      base::Bind(&DeleteShortcutsOnFileThread, shortcut_info));
165}
166
167void UpdateAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
168  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169
170  BrowserThread::PostTask(
171      BrowserThread::FILE,
172      FROM_HERE,
173      base::Bind(&UpdateShortcutsOnFileThread, shortcut_info));
174}
175
176bool CreateShortcutsOnFileThread(
177    const ShellIntegration::ShortcutInfo& shortcut_info,
178    const ShellIntegration::ShortcutLocations& creation_locations) {
179  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
180
181  base::FilePath shortcut_data_dir = GetWebAppDataDirectory(
182      shortcut_info.profile_path, shortcut_info.extension_id,
183      shortcut_info.url);
184  return internals::CreatePlatformShortcuts(shortcut_data_dir, shortcut_info,
185                                            creation_locations);
186}
187
188bool IsValidUrl(const GURL& url) {
189  static const char* const kValidUrlSchemes[] = {
190      chrome::kFileScheme,
191      chrome::kFileSystemScheme,
192      chrome::kFtpScheme,
193      chrome::kHttpScheme,
194      chrome::kHttpsScheme,
195      extensions::kExtensionScheme,
196  };
197
198  for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
199    if (url.SchemeIs(kValidUrlSchemes[i]))
200      return true;
201  }
202
203  return false;
204}
205
206#if defined(TOOLKIT_VIEWS)
207void GetIconsInfo(const WebApplicationInfo& app_info,
208                  IconInfoList* icons) {
209  DCHECK(icons);
210
211  icons->clear();
212  for (size_t i = 0; i < app_info.icons.size(); ++i) {
213    // We only take square shaped icons (i.e. width == height).
214    if (app_info.icons[i].width == app_info.icons[i].height) {
215      icons->push_back(app_info.icons[i]);
216    }
217  }
218
219  std::sort(icons->begin(), icons->end(), &IconPrecedes);
220}
221#endif
222
223#if defined(TOOLKIT_GTK)
224std::string GetWMClassFromAppName(std::string app_name) {
225  file_util::ReplaceIllegalCharactersInPath(&app_name, '_');
226  TrimString(app_name, "_", &app_name);
227  return app_name;
228}
229#endif
230
231string16 GetAppShortcutsSubdirName() {
232  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
233  if (channel == chrome::VersionInfo::CHANNEL_CANARY)
234    return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY);
235  return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME);
236}
237
238}  // namespace web_app
239