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