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