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