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 @@
#include "base/bind.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/ui/web_applications/web_app_ui.h"
#include "chrome/browser/web_applications/web_app.h"
......@@ -61,7 +63,9 @@ void ShortcutManager::Observe(int type,
base::Callback<void(const ShellIntegration::ShortcutInfo&)>
create_or_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 {
create_or_update = base::Bind(&CreateShortcutsInApplicationsMenu);
}
......
......@@ -2429,8 +2429,15 @@ void ExtensionService::FinishDelayedInstallation(
}
void ExtensionService::FinishInstallation(const Extension* extension) {
bool is_update = GetInstalledExtension(extension->id()) != NULL;
extensions::InstalledExtensionInfo details(extension, is_update);
const extensions::Extension* existing_extension =
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(
chrome::NOTIFICATION_EXTENSION_INSTALLED,
content::Source<Profile>(profile_),
......
......@@ -621,6 +621,7 @@ class ExtensionServiceTest
.ptr();
installed_ = installed_info->extension;
was_update_ = installed_info->is_update;
old_name_ = installed_info->old_name;
break;
}
......@@ -713,11 +714,25 @@ class ExtensionServiceTest
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,
InstallState install_state,
int creation_flags) {
int creation_flags,
const std::string& expected_old_name) {
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
......@@ -751,6 +766,18 @@ class ExtensionServiceTest
// Returns an Extension pointer if the install succeeded, NULL otherwise.
const Extension* WaitForCrxInstall(const base::FilePath& path,
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();
std::vector<string16> errors = GetErrors();
const Extension* extension = NULL;
......@@ -762,6 +789,9 @@ class ExtensionServiceTest
// If and only if INSTALL_UPDATED, it should have the is_update flag.
EXPECT_EQ(install_state == INSTALL_UPDATED, was_update_)
<< 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();
if (install_state == INSTALL_WITHOUT_LOAD) {
......@@ -787,6 +817,7 @@ class ExtensionServiceTest
installed_ = NULL;
was_update_ = false;
old_name_ = "";
loaded_.clear();
ExtensionErrorReporter::GetInstance()->ClearErrors();
return extension;
......@@ -1087,6 +1118,7 @@ class ExtensionServiceTest
std::string unloaded_id_;
const Extension* installed_;
bool was_update_;
std::string old_name_;
FeatureSwitch::ScopedOverride override_external_install_prompt_;
private:
......@@ -2515,12 +2547,14 @@ TEST_F(ExtensionServiceTest, UpgradeSignedGood) {
ASSERT_EQ("1.0.0.0", extension->version()->GetString());
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");
InstallCRX(path, INSTALL_UPDATED);
InstallCRX(path, INSTALL_UPDATED, Extension::NO_FLAGS, "My extension 1");
extension = service_->GetExtensionById(id, false);
ASSERT_EQ("1.0.0.1", extension->version()->GetString());
ASSERT_EQ("My updated extension 1", extension->name());
ASSERT_EQ(0u, GetErrors().size());
}
......
......@@ -43,13 +43,14 @@ void DeleteShortcutsOnFileThread(
}
void UpdateShortcutsOnFileThread(
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
shortcut_info.profile_path, shortcut_info.extension_id, GURL());
return web_app::internals::UpdatePlatformShortcuts(
shortcut_data_dir, shortcut_info);
shortcut_data_dir, old_app_title, shortcut_info);
}
} // namespace
......@@ -164,13 +165,14 @@ void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& 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));
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&UpdateShortcutsOnFileThread, shortcut_info));
base::Bind(&UpdateShortcutsOnFileThread, old_app_title, shortcut_info));
}
bool CreateShortcutsOnFileThread(
......
......@@ -9,6 +9,7 @@
#include <vector>
#include "base/files/file_path.h"
#include "base/string16.h"
#include "build/build_config.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/common/web_application_info.h"
......@@ -63,8 +64,10 @@ void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info);
// Updates shortcuts for web application based on given shortcut data. This
// 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.
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
// implement CreateShortcuts() above, and can also be used directly from the
......@@ -128,6 +131,7 @@ void DeletePlatformShortcuts(
// is executed on the FILE thread.
void UpdatePlatformShortcuts(
const base::FilePath& shortcut_data_path,
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info);
// Sanitizes |name| and returns a version of it that is safe to use as an
......
......@@ -20,6 +20,7 @@ void DeletePlatformShortcuts(
void UpdatePlatformShortcuts(
const base::FilePath& web_app_path,
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info) {}
} // namespace internals
......
......@@ -31,6 +31,7 @@ void DeletePlatformShortcuts(
void UpdatePlatformShortcuts(
const base::FilePath& web_app_path,
const string16& /*old_app_title*/,
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
......
......@@ -343,6 +343,7 @@ void DeletePlatformShortcuts(
void UpdatePlatformShortcuts(
const base::FilePath& web_app_path,
const string16& old_app_title,
const ShellIntegration::ShortcutInfo& shortcut_info) {
// TODO(benwells): Implement this when shortcuts / weblings are enabled on
// mac.
......
......@@ -1230,9 +1230,11 @@ ExtensionInfo::~ExtensionInfo() {}
InstalledExtensionInfo::InstalledExtensionInfo(
const Extension* extension,
bool is_update)
bool is_update,
const std::string& old_name)
: extension(extension),
is_update(is_update) {}
is_update(is_update),
old_name(old_name) {}
UnloadedExtensionInfo::UnloadedExtensionInfo(
const Extension* extension,
......
......@@ -553,7 +553,13 @@ struct InstalledExtensionInfo {
// True if the extension is being updated; false if it is being installed.
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 {
......
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