web_app.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_applications/web_app.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <shellapi.h> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector> 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/md5.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/thread.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/scoped_ptr.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chrome_thread.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_util.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_plugin_util.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_registrar.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/dom_operations.h" 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX) 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/env_var.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_LINUX) 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/win_util.h" 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "gfx/icon_util.h" 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst FilePath::CharType kIconChecksumFileExt[] = FILE_PATH_LITERAL(".ico.md5"); 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if |ch| is in visible ASCII range and not one of 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "/ \ : * ? " < > | ; ,". 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsValidFilePathChar(char16 c) { 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (c < 32) 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (c) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '/': 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '\\': 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case ':': 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '*': 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '?': 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '"': 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '<': 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '>': 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case '|': 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case ';': 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case ',': 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns sanitized name that could be used as a file name 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetSanitizedFileName(const string16& name) { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16 file_name; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < name.length(); ++i) { 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch char16 c = name[i]; 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsValidFilePathChar(c)) 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch c = '_'; 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name += c; 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(file_name); 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns relative directory of given web app url. 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetWebAppDir(const GURL& url) { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType host; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType scheme_port; 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host = UTF8ToWide(url.host()); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scheme_port = (url.has_scheme() ? UTF8ToWide(url.scheme()) : L"http") + 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("_") + 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (url.has_port() ? UTF8ToWide(url.port()) : L"80"); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX) 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host = url.host(); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scheme_port = url.scheme() + FILE_PATH_LITERAL("_") + url.port(); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(host).Append(scheme_port); 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns data directory for given web app url 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetWebAppDataDirectory(const FilePath& root_dir, 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url) { 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return root_dir.Append(GetWebAppDir(url)); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Predicator for sorting images from largest to smallest. 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IconPrecedes( 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const webkit_glue::WebApplicationInfo::IconInfo& left, 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const webkit_glue::WebApplicationInfo::IconInfo& right) { 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return left.width < right.width; 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Calculates image checksum using MD5. 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetImageCheckSum(const SkBitmap& image, MD5Digest* digest) { 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(digest); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkAutoLockPixels image_lock(image); 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MD5Sum(image.getPixels(), image.getSize(), digest); 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Saves |image| as an |icon_file| with the checksum. 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SaveIconWithCheckSum(const FilePath& icon_file, const SkBitmap& image) { 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IconUtil::CreateIconFileFromSkBitmap(image, icon_file.value())) 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MD5Digest digest; 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetImageCheckSum(image, &digest); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath cheksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt)); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return file_util::WriteFile(cheksum_file, 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<const char*>(&digest), 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sizeof(digest)) == sizeof(digest); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if |icon_file| is missing or different from |image|. 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ShouldUpdateIcon(const FilePath& icon_file, const SkBitmap& image) { 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath checksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt)); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns true if icon_file or checksum file is missing. 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_util::PathExists(icon_file) || 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !file_util::PathExists(checksum_file)) 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MD5Digest persisted_image_checksum; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sizeof(persisted_image_checksum) != file_util::ReadFile(checksum_file, 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<char*>(&persisted_image_checksum), 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sizeof(persisted_image_checksum))) 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MD5Digest downloaded_image_checksum; 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetImageCheckSum(image, &downloaded_image_checksum); 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update icon if checksums are not equal. 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return memcmp(&persisted_image_checksum, &downloaded_image_checksum, 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sizeof(MD5Digest)) != 0; 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Saves |image| to |icon_file| if the file is outdated and refresh shell's 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// icon cache to ensure correct icon is displayed. Returns true if icon_file 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is up to date or successfully updated. 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image) { 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ShouldUpdateIcon(icon_file, image)) { 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (SaveIconWithCheckSum(icon_file, image)) { 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Refresh shell's icon cache. This call is quite disruptive as user would 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // see explorer rebuilding the icon cache. It would be great that we find 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a better way to achieve this. 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, NULL); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Represents a task that creates web application shortcut. This runs on 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file thread and schedules the callback (if any) on the calling thread 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// when finished (either success or failure). 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CreateShortcutTask : public Task { 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateShortcutTask(const FilePath& profile_path, 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ShellIntegration::ShortcutInfo& shortcut_info, 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::CreateShortcutCallback* callback); 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch class CreateShortcutCallbackTask : public Task { 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateShortcutCallbackTask(web_app::CreateShortcutCallback* callback, 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool success) 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : callback_(callback), 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch success_(success) { 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from Task: 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Run() { 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch callback_->Run(success_); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::CreateShortcutCallback* callback_; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool success_; 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from Task: 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Run(); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns true if shortcut is created successfully. 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool CreateShortcut(); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Path to store persisted data for web app. 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath web_app_path_; 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Out copy of profile path. 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath profile_path_; 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Our copy of short cut data. 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShellIntegration::ShortcutInfo shortcut_info_; 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Callback when task is finished. 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::CreateShortcutCallback* callback_; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop* message_loop_; 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(CreateShortcutTask); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCreateShortcutTask::CreateShortcutTask( 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& profile_path, 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ShellIntegration::ShortcutInfo& shortcut_info, 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::CreateShortcutCallback* callback) 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : web_app_path_(GetWebAppDataDirectory(web_app::GetDataDir(profile_path), 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info.url)), 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_path_(profile_path), 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_(shortcut_info), 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch callback_(callback), 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch message_loop_(MessageLoop::current()) { 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(message_loop_ != NULL); 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CreateShortcutTask::Run() { 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool success = CreateShortcut(); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (callback_ != NULL) 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch message_loop_->PostTask(FROM_HERE, 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new CreateShortcutCallbackTask(callback_, success)); 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateShortcutTask::CreateShortcut() { 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX) 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create()); 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string shortcut_template; 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ShellIntegration::GetDesktopShortcutTemplate(env_getter.get(), 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &shortcut_template)) { 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShellIntegration::CreateDesktopShortcut(shortcut_info_, shortcut_template); 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; // assuming always success. 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN) 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Shortcut paths under which to create shortcuts. 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<FilePath> shortcut_paths; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Locations to add to shortcut_paths. 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch struct { 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool& use_this_location; 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int location_id; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const wchar_t* sub_dir; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } locations[] = { 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_on_desktop, 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::DIR_USER_DESKTOP, 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_in_applications_menu, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::DIR_START_MENU, 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, { 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_in_quick_launch_bar, 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For Win7, create_in_quick_launch_bar means pinning to taskbar. Use 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // base::PATH_START as a flag for this case. 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::PATH_START : base::DIR_APP_DATA, 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL : L"Microsoft\\Internet Explorer\\Quick Launch" 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Populate shortcut_paths. 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < arraysize(locations); ++i) { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (locations[i].use_this_location) { 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath path; 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Skip the Win7 case. 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (locations[i].location_id == base::PATH_START) 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!PathService::Get(locations[i].location_id, &path)) { 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (locations[i].sub_dir != NULL) 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch path = path.Append(locations[i].sub_dir); 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_paths.push_back(path); 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool pin_to_taskbar = 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_in_quick_launch_bar && 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7); 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For Win7's pinning support, any shortcut could be used. So we only create 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the shortcut file when there is no shortcut file will be created. That is, 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user only selects "Pin to taskbar". 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pin_to_taskbar && shortcut_paths.empty()) { 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creates the shortcut in web_app_path_ in this case. 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_paths.push_back(web_app_path_); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shortcut_paths.empty()) { 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ensure web_app_path_ exists. 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_util::PathExists(web_app_path_) && 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !file_util::CreateDirectory(web_app_path_)) { 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Generates file name to use with persisted ico and shortcut file. 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath file_name = GetSanitizedFileName(shortcut_info_.title); 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creates an ico file to use with shortcut. 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath icon_file = web_app_path_.Append(file_name).ReplaceExtension( 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL(".ico")); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!CheckAndSaveIcon(icon_file, shortcut_info_.favicon)) { 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath chrome_exe; 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Working directory. 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath chrome_folder = chrome_exe.DirName(); 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string switches = 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShellIntegration::GetCommandLineArgumentsCommon(shortcut_info_.url, 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.extension_id); 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring wide_switchs(UTF8ToWide(switches)); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sanitize description 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shortcut_info_.description.length() >= MAX_PATH) 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.description.resize(MAX_PATH - 1); 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Generates app id from web app url and profile path. 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring app_id = ShellIntegration::GetAppId( 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::GenerateApplicationNameFromURL(shortcut_info_.url), 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_path_); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath shortcut_to_pin; 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool success = true; 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < shortcut_paths.size(); ++i) { 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath shortcut_file = shortcut_paths[i].Append(file_name). 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReplaceExtension(FILE_PATH_LITERAL(".lnk")); 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int unique_number = download_util::GetUniquePathNumber(shortcut_file); 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (unique_number == -1) { 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch success = false; 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (unique_number > 0) { 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_util::AppendNumberToPath(&shortcut_file, unique_number); 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch success &= file_util::CreateShortcutLink(chrome_exe.value().c_str(), 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_file.value().c_str(), 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome_folder.value().c_str(), 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wide_switchs.c_str(), 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.description.c_str(), 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_file.value().c_str(), 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch app_id.c_str()); 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Any shortcut would work for the pinning. We use the first one. 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (success && pin_to_taskbar && shortcut_to_pin.empty()) 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_to_pin = shortcut_file; 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (success && pin_to_taskbar) { 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!shortcut_to_pin.empty()) { 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch success &= file_util::TaskbarPinShortcutLink( 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_to_pin.value().c_str()); 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch success = false; 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return success; 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTIMPLEMENTED(); 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// UpdateShortcutWorker holds all context data needed for update shortcut. 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// It schedules a pre-update check to find all shortcuts that needs to be 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// updated. If there are such shortcuts, it schedules icon download and 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// update them when icons are downloaded. It observes TAB_CLOSING notification 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and cancels all the work when the underlying tab is closing. 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass UpdateShortcutWorker : public NotificationObserver { 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit UpdateShortcutWorker(TabContents* tab_contents); 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Run(); 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from NotificationObserver: 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Observe(NotificationType type, 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details); 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Downloads icon via TabContents. 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void DownloadIcon(); 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Callback when icon downloaded. 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void OnIconDownloaded(int download_id, bool errored, const SkBitmap& image); 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Checks if shortcuts exists on desktop, start menu and quick launch. 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void CheckExistingShortcuts(); 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update shortcut files and icons. 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateShortcuts(); 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateShortcutsOnFileThread(); 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Callback after shortcuts are updated. 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void OnShortcutsUpdated(bool); 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Deletes the worker on UI thread where it gets created. 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void DeleteMe(); 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void DeleteMeOnUIThread(); 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationRegistrar registrar_; 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Underlying TabContents whose shortcuts will be updated. 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContents* tab_contents_; 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Icons info from tab_contents_'s web app data. 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::IconInfoList unprocessed_icons_; 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cached shortcut data from the tab_contents_. 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShellIntegration::ShortcutInfo shortcut_info_; 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Our copy of profile path. 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath profile_path_; 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // File name of shortcut/ico file based on app title. 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath file_name_; 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Existing shortcuts. 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<FilePath> shortcut_files_; 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(UpdateShortcutWorker); 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUpdateShortcutWorker::UpdateShortcutWorker(TabContents* tab_contents) 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : tab_contents_(tab_contents), 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_path_(tab_contents->profile()->GetPath()) { 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::GetShortcutInfoForTab(tab_contents_, &shortcut_info_); 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::GetIconsInfo(tab_contents_->web_app_info(), &unprocessed_icons_); 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_ = GetSanitizedFileName(shortcut_info_.title); 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::TAB_CLOSING, 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<NavigationController>(&tab_contents_->controller())); 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::Run() { 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Starting by downloading app icon. 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadIcon(); 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::Observe(NotificationType type, 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == NotificationType::TAB_CLOSING && 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<NavigationController>(source).ptr() == 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &tab_contents_->controller()) { 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Underlying tab is closing. 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_ = NULL; 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::DownloadIcon() { 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // FetchIcon must run on UI thread because it relies on TabContents 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to download the icon. 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_contents_ == NULL) { 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DeleteMe(); // We are done if underlying TabContents is gone. 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (unprocessed_icons_.empty()) { 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No app icon. Just use the favicon from TabContents. 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateShortcuts(); 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->fav_icon_helper().DownloadImage( 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unprocessed_icons_.back().url, 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::max(unprocessed_icons_.back().width, 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unprocessed_icons_.back().height), 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewCallback(this, &UpdateShortcutWorker::OnIconDownloaded)); 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unprocessed_icons_.pop_back(); 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::OnIconDownloaded(int download_id, 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool errored, 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkBitmap& image) { 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_contents_ == NULL) { 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DeleteMe(); // We are done if underlying TabContents is gone. 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!errored && !image.isNull()) { 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update icon with download image and update shortcut. 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.favicon = image; 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->SetAppIcon(image); 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateShortcuts(); 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Try the next icon otherwise. 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DownloadIcon(); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::CheckExistingShortcuts() { 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Locations to check to shortcut_paths. 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch struct { 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool& use_this_location; 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int location_id; 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const wchar_t* sub_dir; 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } locations[] = { 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_on_desktop, 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::DIR_USER_DESKTOP, 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, { 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_in_applications_menu, 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::DIR_START_MENU, 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, { 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.create_in_quick_launch_bar, 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For Win7, create_in_quick_launch_bar means pinning to taskbar. 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::DIR_APP_DATA, 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7) ? 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar" : 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch L"Microsoft\\Internet Explorer\\Quick Launch" 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < arraysize(locations); ++i) { 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch locations[i].use_this_location = false; 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath path; 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!PathService::Get(locations[i].location_id, &path)) { 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (locations[i].sub_dir != NULL) 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch path = path.Append(locations[i].sub_dir); 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath shortcut_file = path.Append(file_name_). 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReplaceExtension(FILE_PATH_LITERAL(".lnk")); 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_util::PathExists(shortcut_file)) { 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch locations[i].use_this_location = true; 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_files_.push_back(shortcut_file); 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::UpdateShortcuts() { 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &UpdateShortcutWorker::UpdateShortcutsOnFileThread)); 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::UpdateShortcutsOnFileThread() { 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath web_app_path = GetWebAppDataDirectory( 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::GetDataDir(profile_path_), shortcut_info_.url); 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ensure web_app_path exists. web_app_path could be missing for a legacy 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // shortcut created by gears. 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_util::PathExists(web_app_path) && 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !file_util::CreateDirectory(web_app_path)) { 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath icon_file = web_app_path.Append(file_name_).ReplaceExtension( 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL(".ico")); 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckAndSaveIcon(icon_file, shortcut_info_.favicon); 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update existing shortcuts' description, icon and app id. 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckExistingShortcuts(); 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!shortcut_files_.empty()) { 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Generates app id from web app url and profile path. 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring app_id = ShellIntegration::GetAppId( 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch web_app::GenerateApplicationNameFromURL(shortcut_info_.url), 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_path_); 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sanitize description 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shortcut_info_.description.length() >= MAX_PATH) 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.description.resize(MAX_PATH - 1); 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < shortcut_files_.size(); ++i) { 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::UpdateShortcutLink(NULL, 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_files_[i].value().c_str(), 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_info_.description.c_str(), 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_file.value().c_str(), 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch app_id.c_str()); 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnShortcutsUpdated(true); 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::OnShortcutsUpdated(bool) { 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DeleteMe(); // We are done. 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::DeleteMe() { 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ChromeThread::CurrentlyOn(ChromeThread::UI)) { 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DeleteMeOnUIThread(); 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &UpdateShortcutWorker::DeleteMeOnUIThread)); 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutWorker::DeleteMeOnUIThread() { 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete this; 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; // namespace 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Allows UpdateShortcutWorker without adding refcounting. UpdateShortcutWorker 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// manages its own life time and will delete itself when it's done. 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDISABLE_RUNNABLE_METHOD_REFCOUNT(UpdateShortcutWorker); 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace web_app { 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring GenerateApplicationNameFromURL(const GURL& url) { 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string t; 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch t.append(url.host()); 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch t.append("_"); 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch t.append(url.path()); 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return UTF8ToWide(t); 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CreateShortcut( 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& data_dir, 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ShellIntegration::ShortcutInfo& shortcut_info, 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateShortcutCallback* callback) { 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new CreateShortcutTask(data_dir, shortcut_info, callback)); 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsValidUrl(const GURL& url) { 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static const char* const kValidUrlSchemes[] = { 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::kFileScheme, 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::kFtpScheme, 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::kHttpScheme, 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::kHttpsScheme, 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chrome::kExtensionScheme, 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) { 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url.SchemeIs(kValidUrlSchemes[i])) 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetDataDir(const FilePath& profile_path) { 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return profile_path.Append(chrome::kWebAppDirname); 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_VIEWS) 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetIconsInfo(const webkit_glue::WebApplicationInfo& app_info, 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IconInfoList* icons) { 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(icons); 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icons->clear(); 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < app_info.icons.size(); ++i) { 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only take square shaped icons (i.e. width == height). 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (app_info.icons[i].width == app_info.icons[i].height) { 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icons->push_back(app_info.icons[i]); 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::sort(icons->begin(), icons->end(), &IconPrecedes); 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetShortcutInfoForTab(TabContents* tab_contents, 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShellIntegration::ShortcutInfo* info) { 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(info); // Must provide a valid info. 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const webkit_glue::WebApplicationInfo& app_info = 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents->web_app_info(); 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->url = app_info.app_url.is_empty() ? tab_contents->GetURL() : 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch app_info.app_url; 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->title = app_info.title.empty() ? 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (tab_contents->GetTitle().empty() ? UTF8ToUTF16(info->url.spec()) : 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents->GetTitle()) : 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch app_info.title; 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->description = app_info.description; 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->favicon = tab_contents->GetFavIcon(); 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpdateShortcutForTabContents(TabContents* tab_contents) { 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // UpdateShortcutWorker will delete itself when it's done. 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateShortcutWorker* worker = new UpdateShortcutWorker(tab_contents); 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch worker->Run(); 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; // namespace web_app 764