Commit e7554c3f authored by mgiuca@chromium.org's avatar mgiuca@chromium.org

Windows: When an app is updated and its name changes, recreate shortcuts.

This searches for shortcuts in the usual locations containing the app's old
name, deletes them, and creates new shortcuts in the places where there were
pre-existing shortcuts.

BUG=153981

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202712 0039d316-1c4b-4281-b951-d872f2087c98
parent 695fb334
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/shell_integration.h" #include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/web_applications/web_app_ui.h" #include "chrome/browser/ui/web_applications/web_app_ui.h"
#include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app.h"
...@@ -61,7 +63,9 @@ void ShortcutManager::Observe(int type, ...@@ -61,7 +63,9 @@ void ShortcutManager::Observe(int type,
base::Callback<void(const ShellIntegration::ShortcutInfo&)> base::Callback<void(const ShellIntegration::ShortcutInfo&)>
create_or_update; create_or_update;
if (installed_info->is_update) { if (installed_info->is_update) {
create_or_update = base::Bind(&web_app::UpdateAllShortcuts); string16 old_title = UTF8ToUTF16(installed_info->old_name);
create_or_update = base::Bind(&web_app::UpdateAllShortcuts,
old_title);
} else { } else {
create_or_update = base::Bind(&CreateShortcutsInApplicationsMenu); create_or_update = base::Bind(&CreateShortcutsInApplicationsMenu);
} }
......
...@@ -2429,8 +2429,15 @@ void ExtensionService::FinishDelayedInstallation( ...@@ -2429,8 +2429,15 @@ void ExtensionService::FinishDelayedInstallation(
} }
void ExtensionService::FinishInstallation(const Extension* extension) { void ExtensionService::FinishInstallation(const Extension* extension) {
bool is_update = GetInstalledExtension(extension->id()) != NULL; const extensions::Extension* existing_extension =
extensions::InstalledExtensionInfo details(extension, is_update); GetInstalledExtension(extension->id());
bool is_update = false;
std::string old_name;
if (existing_extension) {
is_update = true;
old_name = existing_extension->name();
}
extensions::InstalledExtensionInfo details(extension, is_update, old_name);
content::NotificationService::current()->Notify( content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_INSTALLED, chrome::NOTIFICATION_EXTENSION_INSTALLED,
content::Source<Profile>(profile_), content::Source<Profile>(profile_),
......
...@@ -621,6 +621,7 @@ class ExtensionServiceTest ...@@ -621,6 +621,7 @@ class ExtensionServiceTest
.ptr(); .ptr();
installed_ = installed_info->extension; installed_ = installed_info->extension;
was_update_ = installed_info->is_update; was_update_ = installed_info->is_update;
old_name_ = installed_info->old_name;
break; break;
} }
...@@ -713,11 +714,25 @@ class ExtensionServiceTest ...@@ -713,11 +714,25 @@ class ExtensionServiceTest
Extension::NO_FLAGS); Extension::NO_FLAGS);
} }
// Attempts to install an extension. Use INSTALL_FAILED if the installation
// is expected to fail.
// If |install_state| is INSTALL_UPDATED, and |expected_old_name| is
// non-empty, expects that the existing extension's title was
// |expected_old_name|.
const Extension* InstallCRX(const base::FilePath& path, const Extension* InstallCRX(const base::FilePath& path,
InstallState install_state, InstallState install_state,
int creation_flags) { int creation_flags,
const std::string& expected_old_name) {
StartCRXInstall(path, creation_flags); StartCRXInstall(path, creation_flags);
return WaitForCrxInstall(path, install_state); return WaitForCrxInstall(path, install_state, expected_old_name);
}
// Attempts to install an extension. Use INSTALL_FAILED if the installation
// is expected to fail.
const Extension* InstallCRX(const base::FilePath& path,
InstallState install_state,
int creation_flags) {
return InstallCRX(path, install_state, creation_flags, "");
} }
// Attempts to install an extension. Use INSTALL_FAILED if the installation // Attempts to install an extension. Use INSTALL_FAILED if the installation
...@@ -751,6 +766,18 @@ class ExtensionServiceTest ...@@ -751,6 +766,18 @@ class ExtensionServiceTest
// Returns an Extension pointer if the install succeeded, NULL otherwise. // Returns an Extension pointer if the install succeeded, NULL otherwise.
const Extension* WaitForCrxInstall(const base::FilePath& path, const Extension* WaitForCrxInstall(const base::FilePath& path,
InstallState install_state) { InstallState install_state) {
return WaitForCrxInstall(path, install_state, "");
}
// Wait for a CrxInstaller to finish. Used by InstallCRX. Set the
// |install_state| to INSTALL_FAILED if the installation is expected to fail.
// If |install_state| is INSTALL_UPDATED, and |expected_old_name| is
// non-empty, expects that the existing extension's title was
// |expected_old_name|.
// Returns an Extension pointer if the install succeeded, NULL otherwise.
const Extension* WaitForCrxInstall(const base::FilePath& path,
InstallState install_state,
const std::string& expected_old_name) {
loop_.RunUntilIdle(); loop_.RunUntilIdle();
std::vector<string16> errors = GetErrors(); std::vector<string16> errors = GetErrors();
const Extension* extension = NULL; const Extension* extension = NULL;
...@@ -762,6 +789,9 @@ class ExtensionServiceTest ...@@ -762,6 +789,9 @@ class ExtensionServiceTest
// If and only if INSTALL_UPDATED, it should have the is_update flag. // If and only if INSTALL_UPDATED, it should have the is_update flag.
EXPECT_EQ(install_state == INSTALL_UPDATED, was_update_) EXPECT_EQ(install_state == INSTALL_UPDATED, was_update_)
<< path.value(); << path.value();
// If INSTALL_UPDATED, old_name_ should match the given string.
if (install_state == INSTALL_UPDATED && !expected_old_name.empty())
EXPECT_EQ(expected_old_name, old_name_);
EXPECT_EQ(0u, errors.size()) << path.value(); EXPECT_EQ(0u, errors.size()) << path.value();
if (install_state == INSTALL_WITHOUT_LOAD) { if (install_state == INSTALL_WITHOUT_LOAD) {
...@@ -787,6 +817,7 @@ class ExtensionServiceTest ...@@ -787,6 +817,7 @@ class ExtensionServiceTest
installed_ = NULL; installed_ = NULL;
was_update_ = false; was_update_ = false;
old_name_ = "";
loaded_.clear(); loaded_.clear();
ExtensionErrorReporter::GetInstance()->ClearErrors(); ExtensionErrorReporter::GetInstance()->ClearErrors();
return extension; return extension;
...@@ -1087,6 +1118,7 @@ class ExtensionServiceTest ...@@ -1087,6 +1118,7 @@ class ExtensionServiceTest
std::string unloaded_id_; std::string unloaded_id_;
const Extension* installed_; const Extension* installed_;
bool was_update_; bool was_update_;
std::string old_name_;
FeatureSwitch::ScopedOverride override_external_install_prompt_; FeatureSwitch::ScopedOverride override_external_install_prompt_;
private: private:
...@@ -2515,12 +2547,14 @@ TEST_F(ExtensionServiceTest, UpgradeSignedGood) { ...@@ -2515,12 +2547,14 @@ TEST_F(ExtensionServiceTest, UpgradeSignedGood) {
ASSERT_EQ("1.0.0.0", extension->version()->GetString()); ASSERT_EQ("1.0.0.0", extension->version()->GetString());
ASSERT_EQ(0u, GetErrors().size()); ASSERT_EQ(0u, GetErrors().size());
// Upgrade to version 1.0.0.1 // Upgrade to version 1.0.0.1.
// Also test that the extension's old and new title are correctly retrieved.
path = data_dir_.AppendASCII("good2.crx"); path = data_dir_.AppendASCII("good2.crx");
InstallCRX(path, INSTALL_UPDATED); InstallCRX(path, INSTALL_UPDATED, Extension::NO_FLAGS, "My extension 1");
extension = service_->GetExtensionById(id, false); extension = service_->GetExtensionById(id, false);
ASSERT_EQ("1.0.0.1", extension->version()->GetString()); ASSERT_EQ("1.0.0.1", extension->version()->GetString());
ASSERT_EQ("My updated extension 1", extension->name());
ASSERT_EQ(0u, GetErrors().size()); ASSERT_EQ(0u, GetErrors().size());
} }
......
...@@ -43,13 +43,14 @@ void DeleteShortcutsOnFileThread( ...@@ -43,13 +43,14 @@ void DeleteShortcutsOnFileThread(
} }
void UpdateShortcutsOnFileThread( void UpdateShortcutsOnFileThread(
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory( base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
shortcut_info.profile_path, shortcut_info.extension_id, GURL()); shortcut_info.profile_path, shortcut_info.extension_id, GURL());
return web_app::internals::UpdatePlatformShortcuts( return web_app::internals::UpdatePlatformShortcuts(
shortcut_data_dir, shortcut_info); shortcut_data_dir, old_app_title, shortcut_info);
} }
} // namespace } // namespace
...@@ -164,13 +165,14 @@ void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) { ...@@ -164,13 +165,14 @@ void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
base::Bind(&DeleteShortcutsOnFileThread, shortcut_info)); base::Bind(&DeleteShortcutsOnFileThread, shortcut_info));
} }
void UpdateAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) { void UpdateAllShortcuts(const string16& old_app_title,
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(&UpdateShortcutsOnFileThread, shortcut_info)); base::Bind(&UpdateShortcutsOnFileThread, old_app_title, shortcut_info));
} }
bool CreateShortcutsOnFileThread( bool CreateShortcutsOnFileThread(
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/string16.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/shell_integration.h" #include "chrome/browser/shell_integration.h"
#include "chrome/common/web_application_info.h" #include "chrome/common/web_application_info.h"
...@@ -63,8 +64,10 @@ void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info); ...@@ -63,8 +64,10 @@ void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info);
// Updates shortcuts for web application based on given shortcut data. This // Updates shortcuts for web application based on given shortcut data. This
// refreshes existing shortcuts and their icons, but does not create new ones. // refreshes existing shortcuts and their icons, but does not create new ones.
// |old_app_title| contains the title of the app prior to this update.
// |shortcut_info| contains information about the shortcuts to update. // |shortcut_info| contains information about the shortcuts to update.
void UpdateAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info); void UpdateAllShortcuts(const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info);
// 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 CreateShortcuts() above, and can also be used directly from the // implement CreateShortcuts() above, and can also be used directly from the
...@@ -128,6 +131,7 @@ void DeletePlatformShortcuts( ...@@ -128,6 +131,7 @@ void DeletePlatformShortcuts(
// is executed on the FILE thread. // is executed on the FILE thread.
void UpdatePlatformShortcuts( void UpdatePlatformShortcuts(
const base::FilePath& shortcut_data_path, const base::FilePath& shortcut_data_path,
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info); 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
......
...@@ -20,6 +20,7 @@ void DeletePlatformShortcuts( ...@@ -20,6 +20,7 @@ void DeletePlatformShortcuts(
void UpdatePlatformShortcuts( void UpdatePlatformShortcuts(
const base::FilePath& web_app_path, const base::FilePath& web_app_path,
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info) {} const ShellIntegration::ShortcutInfo& shortcut_info) {}
} // namespace internals } // namespace internals
......
...@@ -31,6 +31,7 @@ void DeletePlatformShortcuts( ...@@ -31,6 +31,7 @@ void DeletePlatformShortcuts(
void UpdatePlatformShortcuts( void UpdatePlatformShortcuts(
const base::FilePath& web_app_path, const base::FilePath& web_app_path,
const string16& /*old_app_title*/,
const ShellIntegration::ShortcutInfo& shortcut_info) { const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
......
...@@ -343,6 +343,7 @@ void DeletePlatformShortcuts( ...@@ -343,6 +343,7 @@ void DeletePlatformShortcuts(
void UpdatePlatformShortcuts( void UpdatePlatformShortcuts(
const base::FilePath& web_app_path, const base::FilePath& web_app_path,
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info) { 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.
......
...@@ -1230,9 +1230,11 @@ ExtensionInfo::~ExtensionInfo() {} ...@@ -1230,9 +1230,11 @@ ExtensionInfo::~ExtensionInfo() {}
InstalledExtensionInfo::InstalledExtensionInfo( InstalledExtensionInfo::InstalledExtensionInfo(
const Extension* extension, const Extension* extension,
bool is_update) bool is_update,
const std::string& old_name)
: extension(extension), : extension(extension),
is_update(is_update) {} is_update(is_update),
old_name(old_name) {}
UnloadedExtensionInfo::UnloadedExtensionInfo( UnloadedExtensionInfo::UnloadedExtensionInfo(
const Extension* extension, const Extension* extension,
......
...@@ -553,7 +553,13 @@ struct InstalledExtensionInfo { ...@@ -553,7 +553,13 @@ struct InstalledExtensionInfo {
// True if the extension is being updated; false if it is being installed. // True if the extension is being updated; false if it is being installed.
bool is_update; bool is_update;
InstalledExtensionInfo(const Extension* extension, bool is_update); // The name of the extension prior to this update. Will be empty if
// |is_update| is false.
std::string old_name;
InstalledExtensionInfo(const Extension* extension,
bool is_update,
const std::string& old_name);
}; };
struct UnloadedExtensionInfo { struct UnloadedExtensionInfo {
......
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