blob: b8f62d6e4c3035517c88b0e30f4d483794dfb1d7 [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]9922e922013-05-06 08:09:5522#include "chrome/common/chrome_version_info.h"
[email protected]6b414c232013-06-05 07:53:3423#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
[email protected]f18d37ef2014-04-01 11:17:4224#include "chrome/common/pref_names.h"
[email protected]c38831a12011-10-28 12:44:4925#include "content/public/browser/browser_thread.h"
[email protected]090e1ee72014-06-03 13:08:4026#include "extensions/browser/extension_registry.h"
[email protected]326e6f02014-06-20 04:53:3727#include "extensions/browser/image_loader.h"
[email protected]885c0e92012-11-13 20:27:4228#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4129#include "extensions/common/extension.h"
[email protected]090e1ee72014-06-03 13:08:4030#include "extensions/common/extension_set.h"
[email protected]0db486f2014-04-09 19:32:2231#include "extensions/common/manifest_handlers/icons_handler.h"
mukai4245dfe82014-09-05 17:40:5132#include "extensions/grit/extensions_browser_resources.h"
[email protected]f18d37ef2014-04-01 11:17:4233#include "skia/ext/image_operations.h"
34#include "third_party/skia/include/core/SkBitmap.h"
35#include "ui/base/resource/resource_bundle.h"
36#include "ui/gfx/image/image.h"
37#include "ui/gfx/image/image_family.h"
38#include "ui/gfx/image/image_skia.h"
[email protected]cca6f392014-05-28 21:32:2639#include "url/url_constants.h"
[email protected]f18d37ef2014-04-01 11:17:4240
41#if defined(OS_WIN)
42#include "ui/gfx/icon_util.h"
43#endif
[email protected]ed5431872009-11-17 08:39:5144
[email protected]c7264f42014-06-22 21:23:0945#if defined(TOOLKIT_VIEWS)
46#include "chrome/browser/extensions/tab_helper.h"
47#include "chrome/browser/favicon/favicon_tab_helper.h"
48#endif
49
[email protected]631bb742011-11-02 11:29:3950using content::BrowserThread;
51
[email protected]ed5431872009-11-17 08:39:5152namespace {
53
[email protected]f18d37ef2014-04-01 11:17:4254#if defined(OS_MACOSX)
55const int kDesiredSizes[] = {16, 32, 128, 256, 512};
56const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
57#elif defined(OS_LINUX)
58// Linux supports icons of any size. FreeDesktop Icon Theme Specification states
59// that "Minimally you should install a 48x48 icon in the hicolor theme."
60const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
61const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
62#elif defined(OS_WIN)
63const int* kDesiredSizes = IconUtil::kIconDimensions;
64const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
65#else
66const int kDesiredSizes[] = {32};
67const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
68#endif
69
[email protected]16f765632010-09-21 21:31:2770#if defined(TOOLKIT_VIEWS)
[email protected]eabfdae92009-12-11 06:13:5171// Predicator for sorting images from largest to smallest.
[email protected]38789d82010-11-17 06:03:4472bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
73 const WebApplicationInfo::IconInfo& right) {
[email protected]eabfdae92009-12-11 06:13:5174 return left.width < right.width;
75}
[email protected]16f765632010-09-21 21:31:2776#endif
[email protected]eabfdae92009-12-11 06:13:5177
[email protected]238dd7b2014-05-23 07:07:2078base::FilePath GetShortcutDataDir(const web_app::ShortcutInfo& shortcut_info) {
79 return web_app::GetWebAppDataDirectory(shortcut_info.profile_path,
80 shortcut_info.extension_id,
81 shortcut_info.url);
[email protected]e66ba952012-10-09 09:59:4482}
83
[email protected]e6be3fe2014-04-11 13:17:5184void UpdateAllShortcutsForShortcutInfo(
85 const base::string16& old_app_title,
[email protected]2e0424a2014-04-15 13:02:1586 const web_app::ShortcutInfo& shortcut_info,
[email protected]e6be3fe2014-04-11 13:17:5187 const extensions::FileHandlersInfo& file_handlers_info) {
88 BrowserThread::PostTask(
89 BrowserThread::FILE,
90 FROM_HERE,
[email protected]238dd7b2014-05-23 07:07:2091 base::Bind(&web_app::internals::UpdatePlatformShortcuts,
92 GetShortcutDataDir(shortcut_info),
[email protected]e6be3fe2014-04-11 13:17:5193 old_app_title, shortcut_info, file_handlers_info));
[email protected]14885082014-04-08 04:41:2894}
95
[email protected]2e0424a2014-04-15 13:02:1596void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
[email protected]e6be3fe2014-04-11 13:17:5197 extensions::FileHandlersInfo file_handlers_info,
[email protected]5bbfbae2014-06-18 18:26:3898 web_app::InfoCallback callback,
[email protected]f18d37ef2014-04-01 11:17:4299 const gfx::ImageFamily& image_family) {
100 // If the image failed to load (e.g. if the resource being loaded was empty)
101 // use the standard application icon.
102 if (image_family.empty()) {
103 gfx::Image default_icon =
104 ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
105 int size = kDesiredSizes[kNumDesiredSizes - 1];
106 SkBitmap bmp = skia::ImageOperations::Resize(
107 *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
108 size, size);
109 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp);
110 // We are on the UI thread, and this image is needed from the FILE thread,
111 // for creating shortcut icon files.
112 image_skia.MakeThreadSafe();
113 shortcut_info.favicon.Add(gfx::Image(image_skia));
114 } else {
115 shortcut_info.favicon = image_family;
116 }
117
[email protected]e6be3fe2014-04-11 13:17:51118 callback.Run(shortcut_info, file_handlers_info);
119}
120
[email protected]5bbfbae2014-06-18 18:26:38121void IgnoreFileHandlersInfo(
122 const web_app::ShortcutInfoCallback& shortcut_info_callback,
123 const web_app::ShortcutInfo& shortcut_info,
124 const extensions::FileHandlersInfo& file_handlers_info) {
125 shortcut_info_callback.Run(shortcut_info);
126}
127
mitchelljones421df67c2014-12-18 03:06:50128void ScheduleCreatePlatformShortcut(
129 web_app::ShortcutCreationReason reason,
130 const web_app::ShortcutLocations& locations,
131 const web_app::ShortcutInfo& shortcut_info,
132 const extensions::FileHandlersInfo& file_handlers_info) {
133 BrowserThread::PostTask(
134 BrowserThread::FILE, FROM_HERE,
135 base::Bind(
136 base::IgnoreResult(&web_app::internals::CreatePlatformShortcuts),
137 GetShortcutDataDir(shortcut_info), shortcut_info, file_handlers_info,
138 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)
[email protected]2d1d16f2014-04-03 18:18:05180void GetShortcutInfoForTab(content::WebContents* web_contents,
[email protected]9b1b5fe2014-05-15 08:23:17181 ShortcutInfo* info) {
[email protected]2d1d16f2014-04-03 18:18:05182 DCHECK(info); // Must provide a valid info.
183
184 const FaviconTabHelper* favicon_tab_helper =
185 FaviconTabHelper::FromWebContents(web_contents);
186 const extensions::TabHelper* extensions_tab_helper =
187 extensions::TabHelper::FromWebContents(web_contents);
188 const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info();
189
190 info->url = app_info.app_url.is_empty() ? web_contents->GetURL() :
191 app_info.app_url;
192 info->title = app_info.title.empty() ?
193 (web_contents->GetTitle().empty() ? base::UTF8ToUTF16(info->url.spec()) :
194 web_contents->GetTitle()) :
195 app_info.title;
196 info->description = app_info.description;
197 info->favicon.Add(favicon_tab_helper->GetFavicon());
198
199 Profile* profile =
200 Profile::FromBrowserContext(web_contents->GetBrowserContext());
201 info->profile_path = profile->GetPath();
202}
[email protected]c7264f42014-06-22 21:23:09203#endif
[email protected]2d1d16f2014-04-03 18:18:05204
205#if !defined(OS_WIN)
206void UpdateShortcutForTabContents(content::WebContents* web_contents) {}
207#endif
208
[email protected]9b1b5fe2014-05-15 08:23:17209ShortcutInfo ShortcutInfoForExtensionAndProfile(
[email protected]f18d37ef2014-04-01 11:17:42210 const extensions::Extension* app, Profile* profile) {
[email protected]9b1b5fe2014-05-15 08:23:17211 ShortcutInfo shortcut_info;
[email protected]f18d37ef2014-04-01 11:17:42212 shortcut_info.extension_id = app->id();
213 shortcut_info.is_platform_app = app->is_platform_app();
214 shortcut_info.url = extensions::AppLaunchInfo::GetLaunchWebURL(app);
215 shortcut_info.title = base::UTF8ToUTF16(app->name());
216 shortcut_info.description = base::UTF8ToUTF16(app->description());
217 shortcut_info.extension_path = app->path();
218 shortcut_info.profile_path = profile->GetPath();
219 shortcut_info.profile_name =
220 profile->GetPrefs()->GetString(prefs::kProfileName);
221 return shortcut_info;
222}
223
[email protected]e886528e2014-07-01 10:18:41224void GetInfoForApp(const extensions::Extension* extension,
225 Profile* profile,
226 const InfoCallback& callback) {
227 web_app::ShortcutInfo shortcut_info =
228 web_app::ShortcutInfoForExtensionAndProfile(extension, profile);
229 const std::vector<extensions::FileHandlerInfo>* file_handlers =
230 extensions::FileHandlers::GetFileHandlers(extension);
231 extensions::FileHandlersInfo file_handlers_info =
232 file_handlers ? *file_handlers : extensions::FileHandlersInfo();
233
234 std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
235 for (size_t i = 0; i < kNumDesiredSizes; ++i) {
236 int size = kDesiredSizes[i];
237 extensions::ExtensionResource resource =
238 extensions::IconsInfo::GetIconResource(
239 extension, size, ExtensionIconSet::MATCH_EXACTLY);
240 if (!resource.empty()) {
241 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
242 resource,
243 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
244 gfx::Size(size, size),
245 ui::SCALE_FACTOR_100P));
246 }
247 }
248
249 if (info_list.empty()) {
250 size_t i = kNumDesiredSizes - 1;
251 int size = kDesiredSizes[i];
252
253 // If there is no icon at the desired sizes, we will resize what we can get.
254 // Making a large icon smaller is preferred to making a small icon larger,
255 // so look for a larger icon first:
256 extensions::ExtensionResource resource =
257 extensions::IconsInfo::GetIconResource(
258 extension, size, ExtensionIconSet::MATCH_BIGGER);
259 if (resource.empty()) {
260 resource = extensions::IconsInfo::GetIconResource(
261 extension, size, ExtensionIconSet::MATCH_SMALLER);
262 }
263 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
264 resource,
265 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
266 gfx::Size(size, size),
267 ui::SCALE_FACTOR_100P));
268 }
269
270 // |info_list| may still be empty at this point, in which case
271 // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty
272 // image and exit immediately.
273 extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync(
274 extension,
275 info_list,
276 base::Bind(&OnImageLoaded, shortcut_info, file_handlers_info, callback));
277}
278
279void GetShortcutInfoForApp(const extensions::Extension* extension,
280 Profile* profile,
281 const ShortcutInfoCallback& callback) {
282 GetInfoForApp(
[email protected]5bbfbae2014-06-18 18:26:38283 extension, profile, base::Bind(&IgnoreFileHandlersInfo, callback));
[email protected]f18d37ef2014-04-01 11:17:42284}
285
[email protected]090e1ee72014-06-03 13:08:40286bool ShouldCreateShortcutFor(Profile* profile,
287 const extensions::Extension* extension) {
mitchelljones1c301022014-12-11 00:38:47288 bool app_type_requires_shortcut = extension->is_platform_app();
289
290// An additional check here for OS X. We need app shims to be
291// able to show them in the dock.
292#if defined(OS_MACOSX)
mitchelljones58e359152014-12-19 01:10:13293 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
294 switches::kEnableHostedAppShimCreation)) {
295 app_type_requires_shortcut =
296 app_type_requires_shortcut || extension->is_hosted_app();
297 }
mitchelljones1c301022014-12-11 00:38:47298#endif
299
300 return (app_type_requires_shortcut &&
301 extension->location() != extensions::Manifest::COMPONENT &&
302 extensions::ui_util::CanDisplayInAppLauncher(extension, profile));
[email protected]090e1ee72014-06-03 13:08:40303}
304
[email protected]650b2d52013-02-10 03:41:45305base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
306 const std::string& extension_id,
307 const GURL& url) {
[email protected]c002e752012-08-10 12:50:11308 DCHECK(!profile_path.empty());
[email protected]650b2d52013-02-10 03:41:45309 base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
[email protected]2b80909f2012-02-24 04:50:21310
311 if (!extension_id.empty()) {
312 return app_data_dir.AppendASCII(
313 GenerateApplicationNameFromExtensionId(extension_id));
314 }
315
316 std::string host(url.host());
317 std::string scheme(url.has_scheme() ? url.scheme() : "http");
318 std::string port(url.has_port() ? url.port() : "80");
319 std::string scheme_port(scheme + "_" + port);
320
321#if defined(OS_WIN)
[email protected]ab6df3b12013-12-24 23:32:26322 base::FilePath::StringType host_path(base::UTF8ToUTF16(host));
323 base::FilePath::StringType scheme_port_path(base::UTF8ToUTF16(scheme_port));
[email protected]2b80909f2012-02-24 04:50:21324#elif defined(OS_POSIX)
[email protected]650b2d52013-02-10 03:41:45325 base::FilePath::StringType host_path(host);
326 base::FilePath::StringType scheme_port_path(scheme_port);
[email protected]2b80909f2012-02-24 04:50:21327#endif
328
329 return app_data_dir.Append(host_path).Append(scheme_port_path);
330}
331
[email protected]650b2d52013-02-10 03:41:45332base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
333 const extensions::Extension& extension) {
[email protected]2b80909f2012-02-24 04:50:21334 return GetWebAppDataDirectory(
[email protected]6b414c232013-06-05 07:53:34335 profile_path,
336 extension.id(),
337 GURL(extensions::AppLaunchInfo::GetLaunchWebURL(&extension)));
[email protected]2b80909f2012-02-24 04:50:21338}
339
[email protected]9b1b5fe2014-05-15 08:23:17340std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info) {
[email protected]238dd7b2014-05-23 07:07:20341 if (!shortcut_info.extension_id.empty())
[email protected]9b1b5fe2014-05-15 08:23:17342 return GenerateApplicationNameFromExtensionId(shortcut_info.extension_id);
[email protected]238dd7b2014-05-23 07:07:20343 else
[email protected]9b1b5fe2014-05-15 08:23:17344 return GenerateApplicationNameFromURL(shortcut_info.url);
[email protected]a0b60cfd2011-04-06 18:02:41345}
346
[email protected]57ecc4b2010-08-11 03:02:51347std::string GenerateApplicationNameFromURL(const GURL& url) {
[email protected]86b54012009-11-19 09:18:50348 std::string t;
349 t.append(url.host());
350 t.append("_");
351 t.append(url.path());
[email protected]57ecc4b2010-08-11 03:02:51352 return t;
[email protected]86b54012009-11-19 09:18:50353}
354
[email protected]2f1c09d2011-01-14 14:58:14355std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
[email protected]9b1b5fe2014-05-15 08:23:17356 std::string t(kCrxAppPrefix);
[email protected]2f1c09d2011-01-14 14:58:14357 t.append(id);
358 return t;
359}
360
[email protected]edee3faf2011-05-25 21:40:10361std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
362 std::string prefix(kCrxAppPrefix);
363 if (app_name.substr(0, prefix.length()) != prefix)
364 return std::string();
365 return app_name.substr(prefix.length());
366}
367
[email protected]371bd2e2014-07-01 07:10:02368void CreateShortcutsWithInfo(
369 ShortcutCreationReason reason,
370 const ShortcutLocations& locations,
371 const ShortcutInfo& shortcut_info,
372 const extensions::FileHandlersInfo& file_handlers_info) {
[email protected]0b7df36d2012-07-11 09:50:47373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
374
mitchelljones1c301022014-12-11 00:38:47375 // It's possible for the extension to be deleted before we get here.
376 // For example, creating a hosted app from a website. Double check that
377 // it still exists.
378 Profile* profile = g_browser_process->profile_manager()->GetProfileByPath(
379 shortcut_info.profile_path);
380 if (!profile)
381 return;
382
383 extensions::ExtensionRegistry* registry =
384 extensions::ExtensionRegistry::Get(profile);
385 const extensions::Extension* extension = registry->GetExtensionById(
386 shortcut_info.extension_id, extensions::ExtensionRegistry::ENABLED);
387 if (!extension)
388 return;
389
mitchelljones421df67c2014-12-18 03:06:50390 ScheduleCreatePlatformShortcut(reason, locations, shortcut_info,
391 file_handlers_info);
392}
393
394void CreateNonAppShortcut(const ShortcutLocations& locations,
395 const ShortcutInfo& shortcut_info) {
396 ScheduleCreatePlatformShortcut(SHORTCUT_CREATION_AUTOMATED, locations,
397 shortcut_info, extensions::FileHandlersInfo());
[email protected]f8a31292014-04-04 05:45:56398}
399
[email protected]9b1b5fe2014-05-15 08:23:17400void CreateShortcuts(ShortcutCreationReason reason,
401 const ShortcutLocations& locations,
402 Profile* profile,
403 const extensions::Extension* app) {
[email protected]14885082014-04-08 04:41:28404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405
[email protected]090e1ee72014-06-03 13:08:40406 if (!ShouldCreateShortcutFor(profile, app))
407 return;
408
[email protected]e886528e2014-07-01 10:18:41409 GetInfoForApp(
[email protected]5bbfbae2014-06-18 18:26:38410 app, profile, base::Bind(&CreateShortcutsWithInfo, reason, locations));
[email protected]14885082014-04-08 04:41:28411}
412
413void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
[email protected]f8a31292014-04-04 05:45:56414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415
[email protected]238dd7b2014-05-23 07:07:20416 ShortcutInfo shortcut_info =
417 ShortcutInfoForExtensionAndProfile(app, profile);
[email protected]f8a31292014-04-04 05:45:56418 BrowserThread::PostTask(
419 BrowserThread::FILE,
420 FROM_HERE,
[email protected]238dd7b2014-05-23 07:07:20421 base::Bind(&web_app::internals::DeletePlatformShortcuts,
422 GetShortcutDataDir(shortcut_info), shortcut_info));
[email protected]ed5431872009-11-17 08:39:51423}
424
[email protected]0085863a2013-12-06 21:19:03425void UpdateAllShortcuts(const base::string16& old_app_title,
[email protected]14885082014-04-08 04:41:28426 Profile* profile,
427 const extensions::Extension* app) {
[email protected]e66ba952012-10-09 09:59:44428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429
[email protected]e886528e2014-07-01 10:18:41430 GetInfoForApp(app,
431 profile,
432 base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
[email protected]8806d3b2012-04-13 06:46:34433}
434
[email protected]12ea22a2009-11-19 07:17:23435bool IsValidUrl(const GURL& url) {
436 static const char* const kValidUrlSchemes[] = {
[email protected]cca6f392014-05-28 21:32:26437 url::kFileScheme,
438 url::kFileSystemScheme,
439 url::kFtpScheme,
[email protected]e8ca69c2014-05-07 15:31:19440 url::kHttpScheme,
441 url::kHttpsScheme,
[email protected]885c0e92012-11-13 20:27:42442 extensions::kExtensionScheme,
[email protected]12ea22a2009-11-19 07:17:23443 };
444
445 for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
446 if (url.SchemeIs(kValidUrlSchemes[i]))
447 return true;
448 }
449
450 return false;
451}
452
[email protected]be3df2b2010-06-25 21:39:07453#if defined(TOOLKIT_VIEWS)
[email protected]38789d82010-11-17 06:03:44454void GetIconsInfo(const WebApplicationInfo& app_info,
[email protected]eabfdae92009-12-11 06:13:51455 IconInfoList* icons) {
456 DCHECK(icons);
457
458 icons->clear();
459 for (size_t i = 0; i < app_info.icons.size(); ++i) {
460 // We only take square shaped icons (i.e. width == height).
461 if (app_info.icons[i].width == app_info.icons[i].height) {
462 icons->push_back(app_info.icons[i]);
463 }
464 }
465
466 std::sort(icons->begin(), icons->end(), &IconPrecedes);
467}
[email protected]be3df2b2010-06-25 21:39:07468#endif
[email protected]eabfdae92009-12-11 06:13:51469
[email protected]f93a77452013-09-02 05:26:35470#if defined(OS_LINUX)
[email protected]a0b60cfd2011-04-06 18:02:41471std::string GetWMClassFromAppName(std::string app_name) {
[email protected]6bc03de2014-08-07 23:59:15472 base::i18n::ReplaceIllegalCharactersInPath(&app_name, '_');
[email protected]466c9862013-12-03 22:05:28473 base::TrimString(app_name, "_", &app_name);
[email protected]a0b60cfd2011-04-06 18:02:41474 return app_name;
475}
476#endif
477
[email protected]f847e6082011-03-24 00:08:26478} // namespace web_app