blob: 13aee5c7c3f1508cc394dc8af5989089ab353f6a [file] [log] [blame]
[email protected]178f8512012-02-09 01:49:361// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ed5431872009-11-17 08:39:512// 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
[email protected]87212702011-12-08 21:17:197#include "base/bind.h"
[email protected]8806d3b2012-04-13 06:46:348#include "base/bind_helpers.h"
mitchelljones58e359152014-12-19 01:10:139#include "base/command_line.h"
thestig18dfb7a52014-08-26 10:44:0410#include "base/files/file_util.h"
[email protected]a0b60cfd2011-04-06 18:02:4111#include "base/i18n/file_util_icu.h"
[email protected]f18d37ef2014-04-01 11:17:4212#include "base/prefs/pref_service.h"
[email protected]9f0abdb2013-06-10 21:49:3413#include "base/strings/string_util.h"
[email protected]e309f312013-06-07 21:50:0814#include "base/strings/utf_string_conversions.h"
[email protected]7f070d42011-03-09 20:25:3215#include "base/threading/thread.h"
mitchelljones1c301022014-12-11 00:38:4716#include "chrome/browser/browser_process.h"
[email protected]090e1ee72014-06-03 13:08:4017#include "chrome/browser/extensions/extension_ui_util.h"
[email protected]f18d37ef2014-04-01 11:17:4218#include "chrome/browser/profiles/profile.h"
mitchelljones1c301022014-12-11 00:38:4719#include "chrome/browser/profiles/profile_manager.h"
[email protected]eabfdae92009-12-11 06:13:5120#include "chrome/common/chrome_constants.h"
mitchelljones58e359152014-12-19 01:10:1321#include "chrome/common/chrome_switches.h"
[email protected]6b414c232013-06-05 07:53:3422#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
[email protected]f18d37ef2014-04-01 11:17:4223#include "chrome/common/pref_names.h"
[email protected]c38831a12011-10-28 12:44:4924#include "content/public/browser/browser_thread.h"
[email protected]090e1ee72014-06-03 13:08:4025#include "extensions/browser/extension_registry.h"
[email protected]326e6f02014-06-20 04:53:3726#include "extensions/browser/image_loader.h"
[email protected]885c0e92012-11-13 20:27:4227#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4128#include "extensions/common/extension.h"
[email protected]090e1ee72014-06-03 13:08:4029#include "extensions/common/extension_set.h"
[email protected]0db486f2014-04-09 19:32:2230#include "extensions/common/manifest_handlers/icons_handler.h"
mukai4245dfe82014-09-05 17:40:5131#include "extensions/grit/extensions_browser_resources.h"
[email protected]f18d37ef2014-04-01 11:17:4232#include "skia/ext/image_operations.h"
33#include "third_party/skia/include/core/SkBitmap.h"
34#include "ui/base/resource/resource_bundle.h"
35#include "ui/gfx/image/image.h"
36#include "ui/gfx/image/image_family.h"
37#include "ui/gfx/image/image_skia.h"
[email protected]cca6f392014-05-28 21:32:2638#include "url/url_constants.h"
[email protected]f18d37ef2014-04-01 11:17:4239
40#if defined(OS_WIN)
41#include "ui/gfx/icon_util.h"
42#endif
[email protected]ed5431872009-11-17 08:39:5143
[email protected]c7264f42014-06-22 21:23:0944#if defined(TOOLKIT_VIEWS)
45#include "chrome/browser/extensions/tab_helper.h"
sdefresne455826972015-04-10 15:25:1546#include "components/favicon/content/content_favicon_driver.h"
[email protected]c7264f42014-06-22 21:23:0947#endif
48
[email protected]631bb742011-11-02 11:29:3949using content::BrowserThread;
50
[email protected]ed5431872009-11-17 08:39:5151namespace {
52
[email protected]f18d37ef2014-04-01 11:17:4253#if defined(OS_MACOSX)
54const int kDesiredSizes[] = {16, 32, 128, 256, 512};
55const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
56#elif defined(OS_LINUX)
57// Linux supports icons of any size. FreeDesktop Icon Theme Specification states
58// that "Minimally you should install a 48x48 icon in the hicolor theme."
59const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
60const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
61#elif defined(OS_WIN)
62const int* kDesiredSizes = IconUtil::kIconDimensions;
63const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
64#else
65const int kDesiredSizes[] = {32};
66const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
67#endif
68
[email protected]16f765632010-09-21 21:31:2769#if defined(TOOLKIT_VIEWS)
[email protected]eabfdae92009-12-11 06:13:5170// Predicator for sorting images from largest to smallest.
[email protected]38789d82010-11-17 06:03:4471bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
72 const WebApplicationInfo::IconInfo& right) {
[email protected]eabfdae92009-12-11 06:13:5173 return left.width < right.width;
74}
[email protected]16f765632010-09-21 21:31:2775#endif
[email protected]eabfdae92009-12-11 06:13:5176
[email protected]238dd7b2014-05-23 07:07:2077base::FilePath GetShortcutDataDir(const web_app::ShortcutInfo& shortcut_info) {
78 return web_app::GetWebAppDataDirectory(shortcut_info.profile_path,
79 shortcut_info.extension_id,
80 shortcut_info.url);
[email protected]e66ba952012-10-09 09:59:4481}
82
[email protected]e6be3fe2014-04-11 13:17:5183void UpdateAllShortcutsForShortcutInfo(
84 const base::string16& old_app_title,
mgiucab21fe8ee2015-04-09 04:00:4485 scoped_ptr<web_app::ShortcutInfo> shortcut_info,
[email protected]e6be3fe2014-04-11 13:17:5186 const extensions::FileHandlersInfo& file_handlers_info) {
mgiucab21fe8ee2015-04-09 04:00:4487 base::FilePath shortcut_data_dir = GetShortcutDataDir(*shortcut_info);
[email protected]e6be3fe2014-04-11 13:17:5188 BrowserThread::PostTask(
mgiucab21fe8ee2015-04-09 04:00:4489 BrowserThread::FILE, FROM_HERE,
[email protected]238dd7b2014-05-23 07:07:2090 base::Bind(&web_app::internals::UpdatePlatformShortcuts,
mgiucab21fe8ee2015-04-09 04:00:4491 shortcut_data_dir, old_app_title, base::Passed(&shortcut_info),
92 file_handlers_info));
[email protected]14885082014-04-08 04:41:2893}
94
mgiucab21fe8ee2015-04-09 04:00:4495void OnImageLoaded(scoped_ptr<web_app::ShortcutInfo> shortcut_info,
[email protected]e6be3fe2014-04-11 13:17:5196 extensions::FileHandlersInfo file_handlers_info,
[email protected]5bbfbae2014-06-18 18:26:3897 web_app::InfoCallback callback,
[email protected]f18d37ef2014-04-01 11:17:4298 const gfx::ImageFamily& image_family) {
99 // If the image failed to load (e.g. if the resource being loaded was empty)
100 // use the standard application icon.
101 if (image_family.empty()) {
102 gfx::Image default_icon =
103 ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
104 int size = kDesiredSizes[kNumDesiredSizes - 1];
105 SkBitmap bmp = skia::ImageOperations::Resize(
106 *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
107 size, size);
108 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp);
109 // We are on the UI thread, and this image is needed from the FILE thread,
110 // for creating shortcut icon files.
111 image_skia.MakeThreadSafe();
mgiucab21fe8ee2015-04-09 04:00:44112 shortcut_info->favicon.Add(gfx::Image(image_skia));
[email protected]f18d37ef2014-04-01 11:17:42113 } else {
mgiucab21fe8ee2015-04-09 04:00:44114 shortcut_info->favicon = image_family;
[email protected]f18d37ef2014-04-01 11:17:42115 }
116
mgiucab21fe8ee2015-04-09 04:00:44117 callback.Run(shortcut_info.Pass(), file_handlers_info);
[email protected]e6be3fe2014-04-11 13:17:51118}
119
[email protected]5bbfbae2014-06-18 18:26:38120void IgnoreFileHandlersInfo(
121 const web_app::ShortcutInfoCallback& shortcut_info_callback,
mgiucab21fe8ee2015-04-09 04:00:44122 scoped_ptr<web_app::ShortcutInfo> shortcut_info,
[email protected]5bbfbae2014-06-18 18:26:38123 const extensions::FileHandlersInfo& file_handlers_info) {
mgiucab21fe8ee2015-04-09 04:00:44124 shortcut_info_callback.Run(shortcut_info.Pass());
[email protected]5bbfbae2014-06-18 18:26:38125}
126
mitchelljones421df67c2014-12-18 03:06:50127void ScheduleCreatePlatformShortcut(
128 web_app::ShortcutCreationReason reason,
129 const web_app::ShortcutLocations& locations,
mgiucab21fe8ee2015-04-09 04:00:44130 scoped_ptr<web_app::ShortcutInfo> shortcut_info,
mitchelljones421df67c2014-12-18 03:06:50131 const extensions::FileHandlersInfo& file_handlers_info) {
mgiucab21fe8ee2015-04-09 04:00:44132 base::FilePath shortcut_data_dir = GetShortcutDataDir(*shortcut_info);
mitchelljones421df67c2014-12-18 03:06:50133 BrowserThread::PostTask(
134 BrowserThread::FILE, FROM_HERE,
135 base::Bind(
136 base::IgnoreResult(&web_app::internals::CreatePlatformShortcuts),
mgiucab21fe8ee2015-04-09 04:00:44137 shortcut_data_dir, base::Passed(&shortcut_info), file_handlers_info,
mitchelljones421df67c2014-12-18 03:06:50138 locations, reason));
139}
140
[email protected]5bbfbae2014-06-18 18:26:38141} // namespace
142
143namespace web_app {
144
145// The following string is used to build the directory name for
146// shortcuts to chrome applications (the kind which are installed
147// from a CRX). Application shortcuts to URLs use the {host}_{path}
148// for the name of this directory. Hosts can't include an underscore.
149// By starting this string with an underscore, we ensure that there
150// are no naming conflicts.
151static const char kCrxAppPrefix[] = "_crx_";
152
153namespace internals {
154
[email protected]0085863a2013-12-06 21:19:03155base::FilePath GetSanitizedFileName(const base::string16& name) {
[email protected]b6b72222012-02-11 02:04:13156#if defined(OS_WIN)
[email protected]0085863a2013-12-06 21:19:03157 base::string16 file_name = name;
[email protected]b6b72222012-02-11 02:04:13158#else
[email protected]ab6df3b12013-12-24 23:32:26159 std::string file_name = base::UTF16ToUTF8(name);
[email protected]b6b72222012-02-11 02:04:13160#endif
[email protected]6bc03de2014-08-07 23:59:15161 base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
[email protected]650b2d52013-02-10 03:41:45162 return base::FilePath(file_name);
[email protected]b6b72222012-02-11 02:04:13163}
164
[email protected]f847e6082011-03-24 00:08:26165} // namespace internals
166
[email protected]9b1b5fe2014-05-15 08:23:17167ShortcutInfo::ShortcutInfo()
[email protected]2e0424a2014-04-15 13:02:15168 : is_platform_app(false) {
169}
170
[email protected]9b1b5fe2014-05-15 08:23:17171ShortcutInfo::~ShortcutInfo() {}
[email protected]2e0424a2014-04-15 13:02:15172
[email protected]9b1b5fe2014-05-15 08:23:17173ShortcutLocations::ShortcutLocations()
[email protected]2e0424a2014-04-15 13:02:15174 : on_desktop(false),
175 applications_menu_location(APP_MENU_LOCATION_NONE),
[email protected]da0349e2014-06-11 07:38:28176 in_quick_launch_bar(false) {
[email protected]2e0424a2014-04-15 13:02:15177}
178
[email protected]c7264f42014-06-22 21:23:09179#if defined(TOOLKIT_VIEWS)
mgiucab21fe8ee2015-04-09 04:00:44180scoped_ptr<ShortcutInfo> GetShortcutInfoForTab(
181 content::WebContents* web_contents) {
sdefresne455826972015-04-10 15:25:15182 const favicon::FaviconDriver* favicon_driver =
183 favicon::ContentFaviconDriver::FromWebContents(web_contents);
[email protected]2d1d16f2014-04-03 18:18:05184 const extensions::TabHelper* extensions_tab_helper =
185 extensions::TabHelper::FromWebContents(web_contents);
186 const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info();
187
mgiucab21fe8ee2015-04-09 04:00:44188 scoped_ptr<ShortcutInfo> info(new ShortcutInfo);
[email protected]2d1d16f2014-04-03 18:18:05189 info->url = app_info.app_url.is_empty() ? web_contents->GetURL() :
190 app_info.app_url;
191 info->title = app_info.title.empty() ?
192 (web_contents->GetTitle().empty() ? base::UTF8ToUTF16(info->url.spec()) :
193 web_contents->GetTitle()) :
194 app_info.title;
195 info->description = app_info.description;
sdefresne455826972015-04-10 15:25:15196 info->favicon.Add(favicon_driver->GetFavicon());
[email protected]2d1d16f2014-04-03 18:18:05197
198 Profile* profile =
199 Profile::FromBrowserContext(web_contents->GetBrowserContext());
200 info->profile_path = profile->GetPath();
mgiucab21fe8ee2015-04-09 04:00:44201
202 return info;
[email protected]2d1d16f2014-04-03 18:18:05203}
[email protected]c7264f42014-06-22 21:23:09204#endif
[email protected]2d1d16f2014-04-03 18:18:05205
206#if !defined(OS_WIN)
207void UpdateShortcutForTabContents(content::WebContents* web_contents) {}
208#endif
209
mgiucab21fe8ee2015-04-09 04:00:44210scoped_ptr<ShortcutInfo> ShortcutInfoForExtensionAndProfile(
211 const extensions::Extension* app,
212 Profile* profile) {
213 scoped_ptr<ShortcutInfo> shortcut_info(new ShortcutInfo);
214 shortcut_info->extension_id = app->id();
215 shortcut_info->is_platform_app = app->is_platform_app();
dominickna0e147632015-07-20 02:43:22216 shortcut_info->from_bookmark = app->from_bookmark();
mgiucab21fe8ee2015-04-09 04:00:44217 shortcut_info->url = extensions::AppLaunchInfo::GetLaunchWebURL(app);
218 shortcut_info->title = base::UTF8ToUTF16(app->name());
219 shortcut_info->description = base::UTF8ToUTF16(app->description());
220 shortcut_info->extension_path = app->path();
221 shortcut_info->profile_path = profile->GetPath();
222 shortcut_info->profile_name =
[email protected]f18d37ef2014-04-01 11:17:42223 profile->GetPrefs()->GetString(prefs::kProfileName);
mgiucab21fe8ee2015-04-09 04:00:44224 shortcut_info->version_for_display = app->GetVersionForDisplay();
[email protected]f18d37ef2014-04-01 11:17:42225 return shortcut_info;
226}
227
[email protected]e886528e2014-07-01 10:18:41228void GetInfoForApp(const extensions::Extension* extension,
229 Profile* profile,
230 const InfoCallback& callback) {
mgiucab21fe8ee2015-04-09 04:00:44231 scoped_ptr<web_app::ShortcutInfo> shortcut_info(
232 web_app::ShortcutInfoForExtensionAndProfile(extension, profile));
[email protected]e886528e2014-07-01 10:18:41233 const std::vector<extensions::FileHandlerInfo>* file_handlers =
234 extensions::FileHandlers::GetFileHandlers(extension);
235 extensions::FileHandlersInfo file_handlers_info =
236 file_handlers ? *file_handlers : extensions::FileHandlersInfo();
237
238 std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
239 for (size_t i = 0; i < kNumDesiredSizes; ++i) {
240 int size = kDesiredSizes[i];
241 extensions::ExtensionResource resource =
242 extensions::IconsInfo::GetIconResource(
243 extension, size, ExtensionIconSet::MATCH_EXACTLY);
244 if (!resource.empty()) {
245 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
246 resource,
247 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
248 gfx::Size(size, size),
249 ui::SCALE_FACTOR_100P));
250 }
251 }
252
253 if (info_list.empty()) {
254 size_t i = kNumDesiredSizes - 1;
255 int size = kDesiredSizes[i];
256
257 // If there is no icon at the desired sizes, we will resize what we can get.
258 // Making a large icon smaller is preferred to making a small icon larger,
259 // so look for a larger icon first:
260 extensions::ExtensionResource resource =
261 extensions::IconsInfo::GetIconResource(
262 extension, size, ExtensionIconSet::MATCH_BIGGER);
263 if (resource.empty()) {
264 resource = extensions::IconsInfo::GetIconResource(
265 extension, size, ExtensionIconSet::MATCH_SMALLER);
266 }
267 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
268 resource,
269 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
270 gfx::Size(size, size),
271 ui::SCALE_FACTOR_100P));
272 }
273
274 // |info_list| may still be empty at this point, in which case
275 // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty
276 // image and exit immediately.
277 extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync(
mgiucab21fe8ee2015-04-09 04:00:44278 extension, info_list,
279 base::Bind(&OnImageLoaded, base::Passed(&shortcut_info),
280 file_handlers_info, callback));
[email protected]e886528e2014-07-01 10:18:41281}
282
283void GetShortcutInfoForApp(const extensions::Extension* extension,
284 Profile* profile,
285 const ShortcutInfoCallback& callback) {
286 GetInfoForApp(
[email protected]5bbfbae2014-06-18 18:26:38287 extension, profile, base::Bind(&IgnoreFileHandlersInfo, callback));
[email protected]f18d37ef2014-04-01 11:17:42288}
289
benwellsa0e8eaa2015-02-13 04:32:26290bool ShouldCreateShortcutFor(web_app::ShortcutCreationReason reason,
291 Profile* profile,
[email protected]090e1ee72014-06-03 13:08:40292 const extensions::Extension* extension) {
benwellsa0e8eaa2015-02-13 04:32:26293 // Shortcuts should never be created for component apps, or for apps that
294 // cannot be shown in the launcher.
295 if (extension->location() == extensions::Manifest::COMPONENT ||
296 !extensions::ui_util::CanDisplayInAppLauncher(extension, profile)) {
297 return false;
298 }
mitchelljones1c301022014-12-11 00:38:47299
benwellsa0e8eaa2015-02-13 04:32:26300 // Otherwise, always create shortcuts for v2 packaged apps.
301 if (extension->is_platform_app())
302 return true;
303
mitchelljones1c301022014-12-11 00:38:47304#if defined(OS_MACOSX)
mitchelljones3e8befd2015-02-13 01:06:12305 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
306 switches::kDisableHostedAppShimCreation)) {
benwellsa0e8eaa2015-02-13 04:32:26307 return extension->is_hosted_app();
mitchelljones58e359152014-12-19 01:10:13308 }
mitchelljones1c301022014-12-11 00:38:47309
benwellsa0e8eaa2015-02-13 04:32:26310 return false;
311#else
312 // For other platforms, allow shortcut creation if it was explicitly
313 // requested by the user (i.e. is not automatic).
314 return reason == SHORTCUT_CREATION_BY_USER;
315#endif
[email protected]090e1ee72014-06-03 13:08:40316}
317
[email protected]650b2d52013-02-10 03:41:45318base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
319 const std::string& extension_id,
320 const GURL& url) {
[email protected]c002e752012-08-10 12:50:11321 DCHECK(!profile_path.empty());
[email protected]650b2d52013-02-10 03:41:45322 base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
[email protected]2b80909f2012-02-24 04:50:21323
324 if (!extension_id.empty()) {
325 return app_data_dir.AppendASCII(
326 GenerateApplicationNameFromExtensionId(extension_id));
327 }
328
329 std::string host(url.host());
330 std::string scheme(url.has_scheme() ? url.scheme() : "http");
331 std::string port(url.has_port() ? url.port() : "80");
332 std::string scheme_port(scheme + "_" + port);
333
334#if defined(OS_WIN)
[email protected]ab6df3b12013-12-24 23:32:26335 base::FilePath::StringType host_path(base::UTF8ToUTF16(host));
336 base::FilePath::StringType scheme_port_path(base::UTF8ToUTF16(scheme_port));
[email protected]2b80909f2012-02-24 04:50:21337#elif defined(OS_POSIX)
[email protected]650b2d52013-02-10 03:41:45338 base::FilePath::StringType host_path(host);
339 base::FilePath::StringType scheme_port_path(scheme_port);
[email protected]2b80909f2012-02-24 04:50:21340#endif
341
342 return app_data_dir.Append(host_path).Append(scheme_port_path);
343}
344
[email protected]650b2d52013-02-10 03:41:45345base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
346 const extensions::Extension& extension) {
[email protected]2b80909f2012-02-24 04:50:21347 return GetWebAppDataDirectory(
[email protected]6b414c232013-06-05 07:53:34348 profile_path,
349 extension.id(),
350 GURL(extensions::AppLaunchInfo::GetLaunchWebURL(&extension)));
[email protected]2b80909f2012-02-24 04:50:21351}
352
[email protected]9b1b5fe2014-05-15 08:23:17353std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info) {
[email protected]238dd7b2014-05-23 07:07:20354 if (!shortcut_info.extension_id.empty())
[email protected]9b1b5fe2014-05-15 08:23:17355 return GenerateApplicationNameFromExtensionId(shortcut_info.extension_id);
[email protected]238dd7b2014-05-23 07:07:20356 else
[email protected]9b1b5fe2014-05-15 08:23:17357 return GenerateApplicationNameFromURL(shortcut_info.url);
[email protected]a0b60cfd2011-04-06 18:02:41358}
359
[email protected]57ecc4b2010-08-11 03:02:51360std::string GenerateApplicationNameFromURL(const GURL& url) {
[email protected]86b54012009-11-19 09:18:50361 std::string t;
362 t.append(url.host());
363 t.append("_");
364 t.append(url.path());
[email protected]57ecc4b2010-08-11 03:02:51365 return t;
[email protected]86b54012009-11-19 09:18:50366}
367
[email protected]2f1c09d2011-01-14 14:58:14368std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
[email protected]9b1b5fe2014-05-15 08:23:17369 std::string t(kCrxAppPrefix);
[email protected]2f1c09d2011-01-14 14:58:14370 t.append(id);
371 return t;
372}
373
[email protected]edee3faf2011-05-25 21:40:10374std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
375 std::string prefix(kCrxAppPrefix);
376 if (app_name.substr(0, prefix.length()) != prefix)
377 return std::string();
378 return app_name.substr(prefix.length());
379}
380
[email protected]371bd2e2014-07-01 07:10:02381void CreateShortcutsWithInfo(
382 ShortcutCreationReason reason,
383 const ShortcutLocations& locations,
mgiucab21fe8ee2015-04-09 04:00:44384 scoped_ptr<ShortcutInfo> shortcut_info,
[email protected]371bd2e2014-07-01 07:10:02385 const extensions::FileHandlersInfo& file_handlers_info) {
anujk.sharma9fcea9a2015-04-22 06:57:49386 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]0b7df36d2012-07-11 09:50:47387
benwells863dc8b52015-01-20 06:47:01388 // If the shortcut is for an application shortcut with the new bookmark app
389 // flow disabled, there will be no corresponding extension.
mgiucab21fe8ee2015-04-09 04:00:44390 if (!shortcut_info->extension_id.empty()) {
benwells863dc8b52015-01-20 06:47:01391 // It's possible for the extension to be deleted before we get here.
392 // For example, creating a hosted app from a website. Double check that
393 // it still exists.
394 Profile* profile = g_browser_process->profile_manager()->GetProfileByPath(
mgiucab21fe8ee2015-04-09 04:00:44395 shortcut_info->profile_path);
benwells863dc8b52015-01-20 06:47:01396 if (!profile)
397 return;
mitchelljones1c301022014-12-11 00:38:47398
benwells863dc8b52015-01-20 06:47:01399 extensions::ExtensionRegistry* registry =
400 extensions::ExtensionRegistry::Get(profile);
401 const extensions::Extension* extension = registry->GetExtensionById(
mgiucab21fe8ee2015-04-09 04:00:44402 shortcut_info->extension_id, extensions::ExtensionRegistry::EVERYTHING);
benwells863dc8b52015-01-20 06:47:01403 if (!extension)
404 return;
405 }
mitchelljones1c301022014-12-11 00:38:47406
mgiucab21fe8ee2015-04-09 04:00:44407 ScheduleCreatePlatformShortcut(reason, locations, shortcut_info.Pass(),
mitchelljones421df67c2014-12-18 03:06:50408 file_handlers_info);
409}
410
411void CreateNonAppShortcut(const ShortcutLocations& locations,
mgiucab21fe8ee2015-04-09 04:00:44412 scoped_ptr<ShortcutInfo> shortcut_info) {
mitchelljones421df67c2014-12-18 03:06:50413 ScheduleCreatePlatformShortcut(SHORTCUT_CREATION_AUTOMATED, locations,
mgiucab21fe8ee2015-04-09 04:00:44414 shortcut_info.Pass(),
415 extensions::FileHandlersInfo());
[email protected]f8a31292014-04-04 05:45:56416}
417
[email protected]9b1b5fe2014-05-15 08:23:17418void CreateShortcuts(ShortcutCreationReason reason,
419 const ShortcutLocations& locations,
420 Profile* profile,
421 const extensions::Extension* app) {
anujk.sharma9fcea9a2015-04-22 06:57:49422 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]14885082014-04-08 04:41:28423
benwellsa0e8eaa2015-02-13 04:32:26424 if (!ShouldCreateShortcutFor(reason, profile, app))
[email protected]090e1ee72014-06-03 13:08:40425 return;
426
[email protected]e886528e2014-07-01 10:18:41427 GetInfoForApp(
[email protected]5bbfbae2014-06-18 18:26:38428 app, profile, base::Bind(&CreateShortcutsWithInfo, reason, locations));
[email protected]14885082014-04-08 04:41:28429}
430
431void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
anujk.sharma9fcea9a2015-04-22 06:57:49432 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]f8a31292014-04-04 05:45:56433
mgiucab21fe8ee2015-04-09 04:00:44434 scoped_ptr<ShortcutInfo> shortcut_info(
435 ShortcutInfoForExtensionAndProfile(app, profile));
436 base::FilePath shortcut_data_dir = GetShortcutDataDir(*shortcut_info);
[email protected]f8a31292014-04-04 05:45:56437 BrowserThread::PostTask(
mgiucab21fe8ee2015-04-09 04:00:44438 BrowserThread::FILE, FROM_HERE,
[email protected]238dd7b2014-05-23 07:07:20439 base::Bind(&web_app::internals::DeletePlatformShortcuts,
mgiucab21fe8ee2015-04-09 04:00:44440 shortcut_data_dir, base::Passed(&shortcut_info)));
[email protected]ed5431872009-11-17 08:39:51441}
442
[email protected]0085863a2013-12-06 21:19:03443void UpdateAllShortcuts(const base::string16& old_app_title,
[email protected]14885082014-04-08 04:41:28444 Profile* profile,
445 const extensions::Extension* app) {
anujk.sharma9fcea9a2015-04-22 06:57:49446 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]e66ba952012-10-09 09:59:44447
[email protected]e886528e2014-07-01 10:18:41448 GetInfoForApp(app,
449 profile,
450 base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
[email protected]8806d3b2012-04-13 06:46:34451}
452
[email protected]12ea22a2009-11-19 07:17:23453bool IsValidUrl(const GURL& url) {
454 static const char* const kValidUrlSchemes[] = {
[email protected]cca6f392014-05-28 21:32:26455 url::kFileScheme,
456 url::kFileSystemScheme,
457 url::kFtpScheme,
[email protected]e8ca69c2014-05-07 15:31:19458 url::kHttpScheme,
459 url::kHttpsScheme,
[email protected]885c0e92012-11-13 20:27:42460 extensions::kExtensionScheme,
[email protected]12ea22a2009-11-19 07:17:23461 };
462
463 for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
464 if (url.SchemeIs(kValidUrlSchemes[i]))
465 return true;
466 }
467
468 return false;
469}
470
[email protected]be3df2b2010-06-25 21:39:07471#if defined(TOOLKIT_VIEWS)
[email protected]38789d82010-11-17 06:03:44472void GetIconsInfo(const WebApplicationInfo& app_info,
[email protected]eabfdae92009-12-11 06:13:51473 IconInfoList* icons) {
474 DCHECK(icons);
475
476 icons->clear();
477 for (size_t i = 0; i < app_info.icons.size(); ++i) {
478 // We only take square shaped icons (i.e. width == height).
479 if (app_info.icons[i].width == app_info.icons[i].height) {
480 icons->push_back(app_info.icons[i]);
481 }
482 }
483
484 std::sort(icons->begin(), icons->end(), &IconPrecedes);
485}
[email protected]be3df2b2010-06-25 21:39:07486#endif
[email protected]eabfdae92009-12-11 06:13:51487
[email protected]f93a77452013-09-02 05:26:35488#if defined(OS_LINUX)
[email protected]a0b60cfd2011-04-06 18:02:41489std::string GetWMClassFromAppName(std::string app_name) {
[email protected]6bc03de2014-08-07 23:59:15490 base::i18n::ReplaceIllegalCharactersInPath(&app_name, '_');
[email protected]466c9862013-12-03 22:05:28491 base::TrimString(app_name, "_", &app_name);
[email protected]a0b60cfd2011-04-06 18:02:41492 return app_name;
493}
494#endif
495
[email protected]f847e6082011-03-24 00:08:26496} // namespace web_app