Commit c002e757 authored by benwells@chromium.org's avatar benwells@chromium.org

Remove packaged app Windows shortcuts when app is uninstalled.

BUG=130456
TEST=Check app shortcuts are removed when the app is uninstalled. Test extension uninstallation in general.


Review URL: https://chromiumcodereview.appspot.com/10837034

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151021 0039d316-1c4b-4281-b951-d872f2087c98
parent 44cd60e5
...@@ -235,10 +235,16 @@ enum ShortcutOptions { ...@@ -235,10 +235,16 @@ enum ShortcutOptions {
}; };
// Resolve Windows shortcut (.LNK file) // Resolve Windows shortcut (.LNK file)
// This methods tries to resolve a shortcut .LNK file. If the |path| is valid // This methods tries to resolve a shortcut .LNK file. The path of the shortcut
// returns true and puts the target into the |path|, otherwise returns // to resolve is in |shortcut_path|. If |target_path| is not NULL, the target
// false leaving the path as it is. // will be resolved and placed in |target_path|. If |args| is not NULL, the
BASE_EXPORT bool ResolveShortcut(FilePath* path); // arguments will be retrieved and placed in |args|. The function returns true
// if all requested fields are are found successfully.
// Callers can safely use the same variable for both |shortcut_path| and
// |target_path|.
BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
FilePath* target_path,
string16* args);
// Creates (or updates) a Windows shortcut (.LNK file) // Creates (or updates) a Windows shortcut (.LNK file)
// This method creates (or updates) a shortcut link using the information given. // This method creates (or updates) a shortcut link using the information given.
......
...@@ -1617,6 +1617,8 @@ TEST_F(FileUtilTest, ResolveShortcutTest) { ...@@ -1617,6 +1617,8 @@ TEST_F(FileUtilTest, ResolveShortcutTest) {
EXPECT_TRUE(SUCCEEDED(result)); EXPECT_TRUE(SUCCEEDED(result));
result = shell->SetDescription(L"ResolveShortcutTest"); result = shell->SetDescription(L"ResolveShortcutTest");
EXPECT_TRUE(SUCCEEDED(result)); EXPECT_TRUE(SUCCEEDED(result));
result = shell->SetArguments(L"--args");
EXPECT_TRUE(SUCCEEDED(result));
result = persist->Save(link_file.value().c_str(), TRUE); result = persist->Save(link_file.value().c_str(), TRUE);
EXPECT_TRUE(SUCCEEDED(result)); EXPECT_TRUE(SUCCEEDED(result));
if (persist) if (persist)
...@@ -1625,8 +1627,10 @@ TEST_F(FileUtilTest, ResolveShortcutTest) { ...@@ -1625,8 +1627,10 @@ TEST_F(FileUtilTest, ResolveShortcutTest) {
shell->Release(); shell->Release();
bool is_solved; bool is_solved;
is_solved = file_util::ResolveShortcut(&link_file); std::wstring args;
is_solved = file_util::ResolveShortcut(link_file, &link_file, &args);
EXPECT_TRUE(is_solved); EXPECT_TRUE(is_solved);
EXPECT_EQ(L"--args", args);
std::wstring contents; std::wstring contents;
contents = ReadTextFile(link_file); contents = ReadTextFile(link_file);
EXPECT_EQ(L"This is the target.", contents); EXPECT_EQ(L"This is the target.", contents);
...@@ -1649,8 +1653,8 @@ TEST_F(FileUtilTest, CreateShortcutTest) { ...@@ -1649,8 +1653,8 @@ TEST_F(FileUtilTest, CreateShortcutTest) {
target_file.value().c_str(), link_file.value().c_str(), NULL, target_file.value().c_str(), link_file.value().c_str(), NULL,
NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL,
file_util::SHORTCUT_CREATE_ALWAYS)); file_util::SHORTCUT_CREATE_ALWAYS));
FilePath resolved_name = link_file; FilePath resolved_name;
EXPECT_TRUE(file_util::ResolveShortcut(&resolved_name)); EXPECT_TRUE(file_util::ResolveShortcut(link_file, &resolved_name, NULL));
std::wstring read_contents = ReadTextFile(resolved_name); std::wstring read_contents = ReadTextFile(resolved_name);
EXPECT_EQ(file_contents, read_contents); EXPECT_EQ(file_contents, read_contents);
......
...@@ -332,38 +332,53 @@ bool GetFileCreationLocalTime(const std::wstring& filename, ...@@ -332,38 +332,53 @@ bool GetFileCreationLocalTime(const std::wstring& filename,
return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time); return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
} }
bool ResolveShortcut(FilePath* path) { bool ResolveShortcut(const FilePath& shortcut_path,
FilePath* target_path,
string16* args) {
base::ThreadRestrictions::AssertIOAllowed(); base::ThreadRestrictions::AssertIOAllowed();
HRESULT result; HRESULT result;
base::win::ScopedComPtr<IShellLink> i_shell_link; base::win::ScopedComPtr<IShellLink> i_shell_link;
bool is_resolved = false;
// Get pointer to the IShellLink interface // Get pointer to the IShellLink interface.
result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER); CLSCTX_INPROC_SERVER);
if (SUCCEEDED(result)) { if (FAILED(result))
return false;
base::win::ScopedComPtr<IPersistFile> persist; base::win::ScopedComPtr<IPersistFile> persist;
// Query IShellLink for the IPersistFile interface // Query IShellLink for the IPersistFile interface.
result = persist.QueryFrom(i_shell_link); result = persist.QueryFrom(i_shell_link);
if (SUCCEEDED(result)) { if (FAILED(result))
WCHAR temp_path[MAX_PATH]; return false;
// Load the shell link
result = persist->Load(path->value().c_str(), STGM_READ); // Load the shell link.
if (SUCCEEDED(result)) { result = persist->Load(shortcut_path.value().c_str(), STGM_READ);
// Try to find the target of a shortcut if (FAILED(result))
return false;
WCHAR temp[MAX_PATH];
if (target_path) {
// Try to find the target of a shortcut.
result = i_shell_link->Resolve(0, SLR_NO_UI); result = i_shell_link->Resolve(0, SLR_NO_UI);
if (SUCCEEDED(result)) { if (FAILED(result))
result = i_shell_link->GetPath(temp_path, MAX_PATH, return false;
NULL, SLGP_UNCPRIORITY);
*path = FilePath(temp_path); result = i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY);
is_resolved = true; if (FAILED(result))
} return false;
}
} *target_path = FilePath(temp);
} }
return is_resolved; if (args) {
result = i_shell_link->GetArguments(temp, MAX_PATH);
if (FAILED(result))
return false;
*args = string16(temp);
}
return true;
} }
bool CreateOrUpdateShortcutLink(const wchar_t *source, bool CreateOrUpdateShortcutLink(const wchar_t *source,
...@@ -389,7 +404,7 @@ bool CreateOrUpdateShortcutLink(const wchar_t *source, ...@@ -389,7 +404,7 @@ bool CreateOrUpdateShortcutLink(const wchar_t *source,
base::win::ScopedComPtr<IShellLink> i_shell_link; base::win::ScopedComPtr<IShellLink> i_shell_link;
base::win::ScopedComPtr<IPersistFile> i_persist_file; base::win::ScopedComPtr<IPersistFile> i_persist_file;
// Get pointer to the IShellLink interface // Get pointer to the IShellLink interface.
if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER)) || CLSCTX_INPROC_SERVER)) ||
FAILED(i_persist_file.QueryFrom(i_shell_link))) { FAILED(i_persist_file.QueryFrom(i_shell_link))) {
......
...@@ -29,6 +29,23 @@ const int kDesiredSizes[] = {16, 32, 128, 256, 512}; ...@@ -29,6 +29,23 @@ const int kDesiredSizes[] = {16, 32, 128, 256, 512};
#else #else
const int kDesiredSizes[] = {32}; const int kDesiredSizes[] = {32};
#endif #endif
ShellIntegration::ShortcutInfo ShortcutInfoForExtensionAndProfile(
const Extension* extension, Profile* profile) {
ShellIntegration::ShortcutInfo shortcut_info;
shortcut_info.extension_id = extension->id();
shortcut_info.url = GURL(extension->launch_web_url());
shortcut_info.title = UTF8ToUTF16(extension->name());
shortcut_info.description = UTF8ToUTF16(extension->description());
shortcut_info.extension_path = extension->path();
shortcut_info.is_platform_app = extension->is_platform_app();
shortcut_info.create_in_applications_menu = true;
shortcut_info.create_in_quick_launch_bar = true;
shortcut_info.create_on_desktop = true;
shortcut_info.profile_path = profile->GetPath();
return shortcut_info;
}
} // namespace } // namespace
AppShortcutManager::AppShortcutManager(Profile* profile) AppShortcutManager::AppShortcutManager(Profile* profile)
...@@ -57,7 +74,7 @@ void AppShortcutManager::OnImageLoaded(const gfx::Image& image, ...@@ -57,7 +74,7 @@ void AppShortcutManager::OnImageLoaded(const gfx::Image& image,
shortcut_info_.favicon = image; shortcut_info_.favicon = image;
} }
web_app::CreateShortcut(profile_->GetPath(), shortcut_info_); web_app::CreateShortcuts(shortcut_info_);
} }
void AppShortcutManager::Observe(int type, void AppShortcutManager::Observe(int type,
...@@ -76,10 +93,10 @@ void AppShortcutManager::Observe(int type, ...@@ -76,10 +93,10 @@ void AppShortcutManager::Observe(int type,
break; break;
} }
case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
std::string extension_id = const Extension* extension = content::Details<const Extension>(
content::Details<const Extension>(details).ptr()->id(); details).ptr();
if (!disable_shortcut_creation_for_tests) if (!disable_shortcut_creation_for_tests)
web_app::DeleteAllShortcuts(profile_->GetPath(), extension_id); DeleteApplicationShortcuts(extension);
break; break;
} }
default: default:
...@@ -95,17 +112,7 @@ void AppShortcutManager::SetShortcutCreationDisabledForTesting(bool disabled) { ...@@ -95,17 +112,7 @@ void AppShortcutManager::SetShortcutCreationDisabledForTesting(bool disabled) {
void AppShortcutManager::InstallApplicationShortcuts( void AppShortcutManager::InstallApplicationShortcuts(
const Extension* extension) { const Extension* extension) {
shortcut_info_.extension_id = extension->id(); shortcut_info_ = ShortcutInfoForExtensionAndProfile(extension, profile_);
shortcut_info_.url = GURL(extension->launch_web_url());
shortcut_info_.title = UTF8ToUTF16(extension->name());
shortcut_info_.description = UTF8ToUTF16(extension->description());
shortcut_info_.extension_path = extension->path();
shortcut_info_.is_platform_app = extension->is_platform_app();
shortcut_info_.create_in_applications_menu = true;
shortcut_info_.create_in_quick_launch_bar = true;
shortcut_info_.create_on_desktop = true;
shortcut_info_.profile_path = profile_->GetPath();
std::vector<ImageLoadingTracker::ImageInfo> info_list; std::vector<ImageLoadingTracker::ImageInfo> info_list;
for (size_t i = 0; i < arraysize(kDesiredSizes); ++i) { for (size_t i = 0; i < arraysize(kDesiredSizes); ++i) {
int size = kDesiredSizes[i]; int size = kDesiredSizes[i];
...@@ -139,3 +146,10 @@ void AppShortcutManager::InstallApplicationShortcuts( ...@@ -139,3 +146,10 @@ void AppShortcutManager::InstallApplicationShortcuts(
// immediately. // immediately.
tracker_.LoadImages(extension, info_list, ImageLoadingTracker::DONT_CACHE); tracker_.LoadImages(extension, info_list, ImageLoadingTracker::DONT_CACHE);
} }
void AppShortcutManager::DeleteApplicationShortcuts(
const Extension* extension) {
ShellIntegration::ShortcutInfo delete_info =
ShortcutInfoForExtensionAndProfile(extension, profile_);
web_app::DeleteAllShortcuts(delete_info);
}
...@@ -36,6 +36,7 @@ class AppShortcutManager : public ImageLoadingTracker::Observer, ...@@ -36,6 +36,7 @@ class AppShortcutManager : public ImageLoadingTracker::Observer,
private: private:
// Install the shortcuts for an application. // Install the shortcuts for an application.
void InstallApplicationShortcuts(const extensions::Extension* extension); void InstallApplicationShortcuts(const extensions::Extension* extension);
void DeleteApplicationShortcuts(const extensions::Extension* extension);
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
Profile* profile_; Profile* profile_;
......
...@@ -370,7 +370,7 @@ void CreateChromeApplicationShortcutsDialogGtk::CreateDesktopShortcut( ...@@ -370,7 +370,7 @@ void CreateChromeApplicationShortcutsDialogGtk::CreateDesktopShortcut(
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
if (web_app::CreateShortcutOnFileThread(profile_path_, shortcut_info)) { if (web_app::CreateShortcutsOnFileThread(shortcut_info)) {
Release(); Release();
} else { } else {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
......
...@@ -381,7 +381,7 @@ bool CreateApplicationShortcutView::Accept() { ...@@ -381,7 +381,7 @@ bool CreateApplicationShortcutView::Accept() {
shortcut_info_.create_in_quick_launch_bar = false; shortcut_info_.create_in_quick_launch_bar = false;
#endif #endif
web_app::CreateShortcut(profile_->GetPath(), shortcut_info_); web_app::CreateShortcuts(shortcut_info_);
return true; return true;
} }
......
...@@ -315,6 +315,8 @@ void GetShortcutInfoForTab(TabContents* tab_contents, ...@@ -315,6 +315,8 @@ void GetShortcutInfoForTab(TabContents* tab_contents,
info->description = app_info.description; info->description = app_info.description;
info->favicon = info->favicon =
gfx::Image(tab_contents->favicon_tab_helper()->GetFavicon()); gfx::Image(tab_contents->favicon_tab_helper()->GetFavicon());
info->profile_path = tab_contents->profile()->GetPath();
} }
void UpdateShortcutForTabContents(TabContents* tab_contents) { void UpdateShortcutForTabContents(TabContents* tab_contents) {
......
...@@ -28,6 +28,16 @@ bool IconPrecedes(const WebApplicationInfo::IconInfo& left, ...@@ -28,6 +28,16 @@ bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
} }
#endif #endif
void DeleteShortcutsOnFileThread(
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
shortcut_info.profile_path, shortcut_info.extension_id, GURL());
return web_app::internals::DeletePlatformShortcuts(
shortcut_data_dir, shortcut_info);
}
} // namespace } // namespace
namespace web_app { namespace web_app {
...@@ -57,6 +67,7 @@ FilePath GetSanitizedFileName(const string16& name) { ...@@ -57,6 +67,7 @@ FilePath GetSanitizedFileName(const string16& name) {
FilePath GetWebAppDataDirectory(const FilePath& profile_path, FilePath GetWebAppDataDirectory(const FilePath& profile_path,
const std::string& extension_id, const std::string& extension_id,
const GURL& url) { const GURL& url) {
DCHECK(!profile_path.empty());
FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname)); FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
if (!extension_id.empty()) { if (!extension_id.empty()) {
...@@ -118,38 +129,33 @@ std::string GetExtensionIdFromApplicationName(const std::string& app_name) { ...@@ -118,38 +129,33 @@ std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
return app_name.substr(prefix.length()); return app_name.substr(prefix.length());
} }
void CreateShortcut( void CreateShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::FILE, BrowserThread::FILE,
FROM_HERE, FROM_HERE,
base::Bind(base::IgnoreResult(&CreateShortcutOnFileThread), base::Bind(base::IgnoreResult(&CreateShortcutsOnFileThread),
profile_path, shortcut_info)); shortcut_info));
} }
void DeleteAllShortcuts(const FilePath& profile_path, void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
const std::string& extension_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::FILE, BrowserThread::FILE,
FROM_HERE, FROM_HERE,
base::Bind(&internals::DeletePlatformShortcuts, profile_path, base::Bind(&DeleteShortcutsOnFileThread, shortcut_info));
extension_id));
} }
bool CreateShortcutOnFileThread( bool CreateShortcutsOnFileThread(
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
FilePath shortcut_data_dir = GetWebAppDataDirectory( FilePath shortcut_data_dir = GetWebAppDataDirectory(
profile_path, shortcut_info.extension_id, shortcut_info.url); shortcut_info.profile_path, shortcut_info.extension_id,
return internals::CreatePlatformShortcut( shortcut_info.url);
shortcut_data_dir, profile_path, shortcut_info); return internals::CreatePlatformShortcuts(shortcut_data_dir, shortcut_info);
} }
bool IsValidUrl(const GURL& url) { bool IsValidUrl(const GURL& url) {
......
...@@ -46,24 +46,18 @@ std::string GenerateApplicationNameFromExtensionId(const std::string& id); ...@@ -46,24 +46,18 @@ std::string GenerateApplicationNameFromExtensionId(const std::string& id);
// Extracts the extension id from the app name. // Extracts the extension id from the app name.
std::string GetExtensionIdFromApplicationName(const std::string& app_name); std::string GetExtensionIdFromApplicationName(const std::string& app_name);
// Creates a shortcut for web application based on given shortcut data. // Creates shortcuts for web application based on given shortcut data.
// |profile_path| is the path of the creating profile. |shortcut_info) // |shortcut_info| contains information about the shortcut to create.
// contains information about the shortcut to create. void CreateShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info);
void CreateShortcut(
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info);
// Delete all the shortcuts that have been created for the extension with // Delete all the shortcuts that have been created for the given
// |extension_id| in the profile with |profile_path|. // |shortcut_data| in the profile with |profile_path|.
void DeleteAllShortcuts(const FilePath& profile_path, void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info);
const std::string& extension_id);
// Creates a shortcut. Must be called on the file thread. This is used to // Creates a shortcut. Must be called on the file thread. This is used to
// implement CreateShortcut() above, and can also be used directly from the // implement CreateShortcuts() above, and can also be used directly from the
// file thread. |profile_path| is the path of the creating profile. // file thread. |shortcut_info| contains info about the shortcut to create.
// |shortcut_info| constains info about the shortcut to create. bool CreateShortcutsOnFileThread(
bool CreateShortcutOnFileThread(
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info); const ShellIntegration::ShortcutInfo& shortcut_info);
// Returns true if given url is a valid web app url. // Returns true if given url is a valid web app url.
...@@ -91,21 +85,20 @@ bool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image); ...@@ -91,21 +85,20 @@ bool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image);
#endif #endif
// Implemented for each platform, does the platform specific parts of creating // Implemented for each platform, does the platform specific parts of creating
// shortcuts. Used internally by CreateShortcutOnFileThread. // shortcuts. Used internally by CreateShortcutsOnFileThread.
// |shortcut_data_path| is where to store any resources created for the // |shortcut_data_path| is where to store any resources created for the
// shortcut, and is also used as the UserDataDir for platform app shortcuts. // shortcut, and is also used as the UserDataDir for platform app shortcuts.
// |profile_path| is the path of the creating profile. |shortcut_info| // |shortcut_info| contains info about the shortcut to create.
// contains info about the shortcut to create. bool CreatePlatformShortcuts(
bool CreatePlatformShortcut(
const FilePath& shortcut_data_path, const FilePath& shortcut_data_path,
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info); const ShellIntegration::ShortcutInfo& shortcut_info);
// Delete all the shortcuts we have added for this extension. This is the // Delete all the shortcuts we have added for this extension. This is the
// platform specific implementation of the DeleteAllShortcuts function, and // platform specific implementation of the DeleteAllShortcuts function, and
// is executed on the FILE thread.. // is executed on the FILE thread..
void DeletePlatformShortcuts(const FilePath& profile_path, void DeletePlatformShortcuts(
const std::string& extension_id); const FilePath& shortcut_data_path,
const ShellIntegration::ShortcutInfo& shortcut_info);
// Sanitizes |name| and returns a version of it that is safe to use as an // Sanitizes |name| and returns a version of it that is safe to use as an
// on-disk file name . // on-disk file name .
......
...@@ -7,15 +7,15 @@ ...@@ -7,15 +7,15 @@
namespace web_app { namespace web_app {
namespace internals { namespace internals {
bool CreatePlatformShortcut( bool CreatePlatformShortcuts(
const FilePath& web_app_path, const FilePath& web_app_path,
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
return true; return true;
} }
void DeletePlatformShortcuts(const FilePath& profile_path, void DeletePlatformShortcuts(
const std::string& extension_id) {} const FilePath& web_app_path,
const ShellIntegration::ShortcutInfo& shortcut_info) {}
} // namespace internals } // namespace internals
} // namespace web_app } // namespace web_app
...@@ -12,9 +12,8 @@ ...@@ -12,9 +12,8 @@
namespace web_app { namespace web_app {
namespace internals { namespace internals {
bool CreatePlatformShortcut( bool CreatePlatformShortcuts(
const FilePath& web_app_path, const FilePath& web_app_path,
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
...@@ -29,9 +28,11 @@ bool CreatePlatformShortcut( ...@@ -29,9 +28,11 @@ bool CreatePlatformShortcut(
shortcut_info, shortcut_template); shortcut_info, shortcut_template);
} }
void DeletePlatformShortcuts(const FilePath& profile_path, void DeletePlatformShortcuts(
const std::string& extension_id) { const FilePath& web_app_path,
ShellIntegrationLinux::DeleteDesktopShortcuts(profile_path, extension_id); const ShellIntegration::ShortcutInfo& shortcut_info) {
ShellIntegrationLinux::DeleteDesktopShortcuts(shortcut_info.profile_path,
shortcut_info.extension_id);
} }
} // namespace internals } // namespace internals
......
...@@ -251,9 +251,8 @@ void WebAppShortcutCreator::RevealGeneratedBundleInFinder( ...@@ -251,9 +251,8 @@ void WebAppShortcutCreator::RevealGeneratedBundleInFinder(
namespace web_app { namespace web_app {
namespace internals { namespace internals {
bool CreatePlatformShortcut( bool CreatePlatformShortcuts(
const FilePath& web_app_path, const FilePath& web_app_path,
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
string16 bundle_id = UTF8ToUTF16(base::mac::BaseBundleID()); string16 bundle_id = UTF8ToUTF16(base::mac::BaseBundleID());
...@@ -262,8 +261,9 @@ bool CreatePlatformShortcut( ...@@ -262,8 +261,9 @@ bool CreatePlatformShortcut(
return shortcut_creator.CreateShortcut(); return shortcut_creator.CreateShortcut();
} }
void DeletePlatformShortcuts(const FilePath& profile_path, void DeletePlatformShortcuts(
const std::string& extension_id) { const FilePath& web_app_path,
const ShellIntegration::ShortcutInfo& shortcut_info) {
// TODO(benwells): Implement this when shortcuts / weblings are enabled on // TODO(benwells): Implement this when shortcuts / weblings are enabled on
// mac. // mac.
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "ui/gfx/icon_util.h" #include "ui/gfx/icon_util.h"
...@@ -67,37 +68,8 @@ bool ShouldUpdateIcon(const FilePath& icon_file, const SkBitmap& image) { ...@@ -67,37 +68,8 @@ bool ShouldUpdateIcon(const FilePath& icon_file, const SkBitmap& image) {
sizeof(base::MD5Digest)) != 0; sizeof(base::MD5Digest)) != 0;
} }
} // namespace std::vector<FilePath> GetShortcutPaths(
ShellIntegration::ShortcutInfo shortcut_info) {
namespace web_app {
namespace internals {
// Saves |image| to |icon_file| if the file is outdated and refresh shell's
// icon cache to ensure correct icon is displayed. Returns true if icon_file
// is up to date or successfully updated.
bool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image) {
if (ShouldUpdateIcon(icon_file, image)) {
if (SaveIconWithCheckSum(icon_file, image)) {
// Refresh shell's icon cache. This call is quite disruptive as user would
// see explorer rebuilding the icon cache. It would be great that we find
// a better way to achieve this.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT,
NULL, NULL);
} else {
return false;
}
}
return true;
}
bool CreatePlatformShortcut(
const FilePath& web_app_path,
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
// Shortcut paths under which to create shortcuts. // Shortcut paths under which to create shortcuts.
std::vector<FilePath> shortcut_paths; std::vector<FilePath> shortcut_paths;
...@@ -136,7 +108,7 @@ bool CreatePlatformShortcut( ...@@ -136,7 +108,7 @@ bool CreatePlatformShortcut(
continue; continue;
if (!PathService::Get(locations[i].location_id, &path)) { if (!PathService::Get(locations[i].location_id, &path)) {
return false; continue;
} }
if (locations[i].sub_dir != NULL) if (locations[i].sub_dir != NULL)
...@@ -146,8 +118,81 @@ bool CreatePlatformShortcut( ...@@ -146,8 +118,81 @@ bool CreatePlatformShortcut(
} }
} }
bool pin_to_taskbar = return shortcut_paths;
shortcut_info.create_in_quick_launch_bar && }
bool ShortcutIsForProfile(const FilePath& shortcut_file_name,
const FilePath& profile_path) {
string16 cmd_line_string;
if (file_util::ResolveShortcut(shortcut_file_name, NULL, &cmd_line_string)) {
cmd_line_string = L"program " + cmd_line_string;
CommandLine shortcut_cmd_line = CommandLine::FromString(cmd_line_string);
return shortcut_cmd_line.HasSwitch(switches::kProfileDirectory) &&
shortcut_cmd_line.GetSwitchValuePath(switches::kProfileDirectory) ==
profile_path.BaseName();
}
return false;
}
std::vector<FilePath> MatchingShortcutsForProfileAndExtension(
const FilePath& shortcut_path,
const FilePath& profile_path,
const string16& shortcut_name) {
std::vector<FilePath> shortcut_paths;
FilePath base_path = shortcut_path.
Append(web_app::internals::GetSanitizedFileName(shortcut_name)).
ReplaceExtension(FILE_PATH_LITERAL(".lnk"));
const int fileNamesToCheck = 10;
for (int i = 0; i < fileNamesToCheck; ++i) {
FilePath shortcut_file = base_path;
if (i) {
shortcut_file = shortcut_file.InsertBeforeExtensionASCII(
StringPrintf(" (%d)", i));
}
if (file_util::PathExists(shortcut_file) &&
ShortcutIsForProfile(shortcut_file, profile_path)) {
shortcut_paths.push_back(shortcut_file);
}
}
return shortcut_paths;
}
} // namespace
namespace web_app {
namespace internals {
// Saves |image| to |icon_file| if the file is outdated and refresh shell's
// icon cache to ensure correct icon is displayed. Returns true if icon_file
// is up to date or successfully updated.
bool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image) {
if (ShouldUpdateIcon(icon_file, image)) {
if (SaveIconWithCheckSum(icon_file, image)) {
// Refresh shell's icon cache. This call is quite disruptive as user would
// see explorer rebuilding the icon cache. It would be great that we find
// a better way to achieve this.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT,
NULL, NULL);
} else {
return false;
}
}
return true;
}
bool CreatePlatformShortcuts(
const FilePath& web_app_path,
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
// Shortcut paths under which to create shortcuts.
std::vector<FilePath> shortcut_paths = GetShortcutPaths(shortcut_info);
bool pin_to_taskbar = shortcut_info.create_in_quick_launch_bar &&
(base::win::GetVersion() >= base::win::VERSION_WIN7); (base::win::GetVersion() >= base::win::VERSION_WIN7);
// For Win7's pinning support, any shortcut could be used. So we only create // For Win7's pinning support, any shortcut could be used. So we only create
...@@ -158,9 +203,8 @@ bool CreatePlatformShortcut( ...@@ -158,9 +203,8 @@ bool CreatePlatformShortcut(
shortcut_paths.push_back(web_app_path); shortcut_paths.push_back(web_app_path);
} }
if (shortcut_paths.empty()) { if (shortcut_paths.empty())
return false; return false;
}
// Ensure web_app_path exists // Ensure web_app_path exists
if (!file_util::PathExists(web_app_path) && if (!file_util::PathExists(web_app_path) &&
...@@ -181,9 +225,8 @@ bool CreatePlatformShortcut( ...@@ -181,9 +225,8 @@ bool CreatePlatformShortcut(
} }
FilePath chrome_exe; FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { if (!PathService::Get(base::FILE_EXE, &chrome_exe))
return false; return false;
}
// Working directory. // Working directory.
FilePath chrome_folder = chrome_exe.DirName(); FilePath chrome_folder = chrome_exe.DirName();
...@@ -208,10 +251,9 @@ bool CreatePlatformShortcut( ...@@ -208,10 +251,9 @@ bool CreatePlatformShortcut(
std::string app_name = std::string app_name =
web_app::GenerateApplicationNameFromInfo(shortcut_info); web_app::GenerateApplicationNameFromInfo(shortcut_info);
string16 app_id = ShellIntegration::GetAppModelIdForProfile( string16 app_id = ShellIntegration::GetAppModelIdForProfile(
UTF8ToUTF16(app_name), profile_path); UTF8ToUTF16(app_name), shortcut_info.profile_path);
FilePath shortcut_to_pin; FilePath shortcut_to_pin;
bool success = true; bool success = true;
for (size_t i = 0; i < shortcut_paths.size(); ++i) { for (size_t i = 0; i < shortcut_paths.size(); ++i) {
FilePath shortcut_file = shortcut_paths[i].Append(file_name). FilePath shortcut_file = shortcut_paths[i].Append(file_name).
...@@ -255,9 +297,34 @@ bool CreatePlatformShortcut( ...@@ -255,9 +297,34 @@ bool CreatePlatformShortcut(
return success; return success;
} }
void DeletePlatformShortcuts(const FilePath& profile_path, void DeletePlatformShortcuts(
const std::string& extension_id) { const FilePath& web_app_path,
// TODO(benwells): Implement this. const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
// Get all possible locations for shortcuts.
ShellIntegration::ShortcutInfo all_shortcuts_info = shortcut_info;
all_shortcuts_info.create_in_applications_menu = true;
all_shortcuts_info.create_in_quick_launch_bar = true;
all_shortcuts_info.create_on_desktop = true;
std::vector<FilePath> shortcut_locations = GetShortcutPaths(
all_shortcuts_info);
if (base::win::GetVersion() >= base::win::VERSION_WIN7)
shortcut_locations.push_back(web_app_path);
for (std::vector<FilePath>::const_iterator i = shortcut_locations.begin();
i != shortcut_locations.end(); ++i) {
std::vector<FilePath> shortcut_files =
MatchingShortcutsForProfileAndExtension(*i, shortcut_info.profile_path,
shortcut_info.title);
for (std::vector<FilePath>::const_iterator j = shortcut_files.begin();
j != shortcut_files.end(); ++j) {
// Any shortcut could have been pinned, either by chrome or the user, so
// they are all unpinned.
file_util::TaskbarUnpinShortcutLink(j->value().c_str());
file_util::Delete(*j, false);
}
}
} }
} // namespace internals } // namespace internals
......
...@@ -200,7 +200,7 @@ bool URLRequestFileJob::IsRedirectResponse(GURL* location, ...@@ -200,7 +200,7 @@ bool URLRequestFileJob::IsRedirectResponse(GURL* location,
FilePath new_path = file_path_; FilePath new_path = file_path_;
bool resolved; bool resolved;
resolved = file_util::ResolveShortcut(&new_path); resolved = file_util::ResolveShortcut(new_path, &new_path, NULL);
// If shortcut is not resolved succesfully, do not redirect. // If shortcut is not resolved succesfully, do not redirect.
if (!resolved) if (!resolved)
......
...@@ -686,7 +686,7 @@ bool SelectFileDialogImpl::RunSelectFolderDialog(const std::wstring& title, ...@@ -686,7 +686,7 @@ bool SelectFileDialogImpl::RunSelectFolderDialog(const std::wstring& title,
// According to MSDN, win2000 will not resolve shortcuts, so we do it // According to MSDN, win2000 will not resolve shortcuts, so we do it
// ourself. // ourself.
file_util::ResolveShortcut(path); file_util::ResolveShortcut(*path, path, NULL);
} }
CoTaskMemFree(list); CoTaskMemFree(list);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment