summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_provider.cc2
-rw-r--r--chrome/browser/automation/automation_provider_observers.cc39
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc2
-rw-r--r--chrome/browser/background_application_list_model_unittest.cc12
-rw-r--r--chrome/browser/browser_browsertest.cc2
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc2
-rw-r--r--chrome/browser/extensions/extension_context_menu_model.cc3
-rw-r--r--chrome/browser/extensions/extension_management_api.cc3
-rw-r--r--chrome/browser/extensions/extension_service.cc40
-rw-r--r--chrome/browser/extensions/extension_service.h10
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc20
-rw-r--r--chrome/browser/extensions/extension_updater_unittest.cc8
-rw-r--r--chrome/browser/extensions/extensions_ui.cc2
-rw-r--r--chrome/browser/sync/glue/extension_sync.cc2
-rw-r--r--chrome/browser/themes/theme_service.cc2
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm2
-rw-r--r--chrome/browser/ui/webui/app_launcher_handler.cc4
-rw-r--r--chrome/browser/ui/webui/options/extension_settings_handler.cc2
-rw-r--r--chrome/common/extensions/extension_constants.cc4
-rw-r--r--chrome/common/extensions/extension_constants.h3
-rw-r--r--chrome/test/functional/PYAUTO_TESTS1
-rw-r--r--chrome/test/functional/ntp.py18
-rw-r--r--chrome/test/pyautolib/pyauto.py12
-rw-r--r--content/common/notification_type.h5
24 files changed, 140 insertions, 60 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 06842ac..59e3134 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -820,7 +820,7 @@ void AutomationProvider::UninstallExtension(int extension_handle,
ExtensionService* service = profile_->GetExtensionService();
if (extension && service) {
ExtensionUnloadNotificationObserver observer;
- service->UninstallExtension(extension->id(), false);
+ service->UninstallExtension(extension->id(), false, NULL);
// The extension unload notification should have been sent synchronously
// with the uninstall. Just to be safe, check that it was received.
*success = observer.did_receive_unload_notification();
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index 3eff584..3e8d840 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -509,6 +509,8 @@ ExtensionUninstallObserver::ExtensionUninstallObserver(
id_(id) {
registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED,
+ NotificationService::AllSources());
}
ExtensionUninstallObserver::~ExtensionUninstallObserver() {
@@ -523,13 +525,36 @@ void ExtensionUninstallObserver::Observe(
return;
}
- DCHECK(type == NotificationType::EXTENSION_UNINSTALLED);
- UninstalledExtensionInfo* info =
- Details<UninstalledExtensionInfo>(details).ptr();
- if (id_ == info->extension_id) {
- AutomationJSONReply(automation_, reply_message_.release())
- .SendSuccess(NULL);
- delete this;
+ switch (type.value) {
+ case NotificationType::EXTENSION_UNINSTALLED: {
+ UninstalledExtensionInfo* info =
+ Details<UninstalledExtensionInfo>(details).ptr();
+ if (id_ == info->extension_id) {
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->SetBoolean("success", true);
+ AutomationJSONReply(automation_, reply_message_.release())
+ .SendSuccess(return_value.get());
+ delete this;
+ return;
+ }
+ break;
+ }
+
+ case NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED: {
+ const Extension* extension = Details<Extension>(details).ptr();
+ if (id_ == extension->id()) {
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->SetBoolean("success", false);
+ AutomationJSONReply(automation_, reply_message_.release())
+ .SendSuccess(return_value.get());
+ delete this;
+ return;
+ }
+ break;
+ }
+
+ default:
+ NOTREACHED();
}
}
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 8d22f6e..67ffa9e 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -3910,7 +3910,7 @@ void TestingAutomationProvider::UninstallExtensionById(
// Wait for a notification indicating that the extension with the given ID
// has been uninstalled. This observer will delete itself.
new ExtensionUninstallObserver(this, reply_message, id);
- service->UninstallExtension(id, false);
+ service->UninstallExtension(id, false, NULL);
}
// Sample json input:
diff --git a/chrome/browser/background_application_list_model_unittest.cc b/chrome/browser/background_application_list_model_unittest.cc
index a552bcc..1ed6ae0 100644
--- a/chrome/browser/background_application_list_model_unittest.cc
+++ b/chrome/browser/background_application_list_model_unittest.cc
@@ -141,23 +141,23 @@ TEST_F(BackgroundApplicationListModelTest, LoadExplicitExtensions) {
ASSERT_EQ(2U, model->size());
// Remove in FIFO order.
ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext1));
- service->UninstallExtension(ext1->id(), false);
+ service->UninstallExtension(ext1->id(), false, NULL);
ASSERT_EQ(4U, service->extensions()->size());
ASSERT_EQ(2U, model->size());
ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp1));
- service->UninstallExtension(bgapp1->id(), false);
+ service->UninstallExtension(bgapp1->id(), false, NULL);
ASSERT_EQ(3U, service->extensions()->size());
ASSERT_EQ(1U, model->size());
ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext2));
- service->UninstallExtension(ext2->id(), false);
+ service->UninstallExtension(ext2->id(), false, NULL);
ASSERT_EQ(2U, service->extensions()->size());
ASSERT_EQ(1U, model->size());
ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp2));
- service->UninstallExtension(bgapp2->id(), false);
+ service->UninstallExtension(bgapp2->id(), false, NULL);
ASSERT_EQ(1U, service->extensions()->size());
ASSERT_EQ(0U, model->size());
ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext3));
- service->UninstallExtension(ext3->id(), false);
+ service->UninstallExtension(ext3->id(), false, NULL);
ASSERT_EQ(0U, service->extensions()->size());
ASSERT_EQ(0U, model->size());
}
@@ -232,7 +232,7 @@ TEST_F(BackgroundApplicationListModelTest, LoadRandomExtension) {
extensions.erase(cursor);
--count;
ASSERT_EQ(count, extensions.size());
- service->UninstallExtension(extension->id(), false);
+ service->UninstallExtension(extension->id(), false, NULL);
ASSERT_EQ(count, service->extensions()->size());
ASSERT_EQ(expected, model->size());
}
diff --git a/chrome/browser/browser_browsertest.cc b/chrome/browser/browser_browsertest.cc
index 4b1c38c..b4c5cbb 100644
--- a/chrome/browser/browser_browsertest.cc
+++ b/chrome/browser/browser_browsertest.cc
@@ -502,7 +502,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) {
// Uninstall the extension and make sure TabClosing is sent.
ExtensionService* service = browser()->profile()->GetExtensionService();
- service->UninstallExtension(GetExtension()->id(), false);
+ service->UninstallExtension(GetExtension()->id(), false, NULL);
EXPECT_EQ(1, observer.closing_count());
model->RemoveObserver(&observer);
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 670789a..277e7d4 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -279,7 +279,7 @@ void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
ExtensionService* service = browser()->profile()->GetExtensionService();
- service->UninstallExtension(extension_id, false);
+ service->UninstallExtension(extension_id, false, NULL);
}
void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index d057e58..6f2a0d0 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -152,7 +152,8 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) {
void ExtensionContextMenuModel::ExtensionDialogAccepted() {
if (GetExtension())
- profile_->GetExtensionService()->UninstallExtension(extension_id_, false);
+ profile_->GetExtensionService()->UninstallExtension(extension_id_, false,
+ NULL);
Release();
}
diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc
index ceaa864..70722bc 100644
--- a/chrome/browser/extensions/extension_management_api.cc
+++ b/chrome/browser/extensions/extension_management_api.cc
@@ -242,7 +242,8 @@ bool UninstallFunction::RunImpl() {
return false;
}
- service()->UninstallExtension(extension_id, false /* external_uninstall */);
+ service()->UninstallExtension(extension_id, false /* external_uninstall */,
+ NULL);
return true;
}
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 361e165..9887b4c 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -258,7 +258,7 @@ void ExtensionService::CheckExternalUninstall(const std::string& id) {
}
// This is an external extension that we don't have registered. Uninstall.
- UninstallExtension(id, true);
+ UninstallExtension(id, true, NULL);
}
void ExtensionService::ClearProvidersForTesting() {
@@ -362,6 +362,9 @@ bool ExtensionService::IsInstalledApp(const GURL& url) {
}
// static
+// This function is used to implement the command-line switch
+// --uninstall-extension. The LOG statements within this function are used to
+// inform the user if the uninstall cannot be done.
bool ExtensionService::UninstallExtensionHelper(
ExtensionService* extensions_service,
const std::string& extension_id) {
@@ -371,19 +374,21 @@ bool ExtensionService::UninstallExtensionHelper(
if (!extension)
extension = extensions_service->GetTerminatedExtension(extension_id);
- // We can't call UninstallExtension with an invalid extension ID. We should
- // not allow an uninstall of a policy-controlled extension.
+ // We can't call UninstallExtension with an invalid extension ID.
if (!extension) {
LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
<< "id: " << extension_id;
return false;
- } else if (!Extension::UserMayDisable(extension->location())) {
- LOG(WARNING) << "Attempted uninstallation of an extension that is non-"
- << "usermanagable with id: " << extension_id;
- return false;
}
- extensions_service->UninstallExtension(extension_id, false);
+ // The following call to UninstallExtension will not allow an uninstall of a
+ // policy-controlled extension.
+ std::string error;
+ if (!extensions_service->UninstallExtension(extension_id, false, &error)) {
+ LOG(WARNING) << "Cannot uninstall extension with id " << extension_id
+ << ": " << error;
+ return false;
+ }
return true;
}
@@ -607,8 +612,9 @@ void ExtensionService::ReloadExtension(const std::string& extension_id) {
}
}
-void ExtensionService::UninstallExtension(const std::string& extension_id,
- bool external_uninstall) {
+bool ExtensionService::UninstallExtension(const std::string& extension_id,
+ bool external_uninstall,
+ std::string* error) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const Extension* extension =
@@ -627,8 +633,16 @@ void ExtensionService::UninstallExtension(const std::string& extension_id,
// Policy change which triggers an uninstall will always set
// |external_uninstall| to true so this is the only way to uninstall
// managed extensions.
- if (!Extension::UserMayDisable(location) && !external_uninstall)
- return;
+ if (!Extension::UserMayDisable(location) && !external_uninstall) {
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED,
+ Source<Profile>(profile_),
+ Details<const Extension>(extension));
+ if (error != NULL) {
+ *error = errors::kCannotUninstallManagedExtension;
+ }
+ return false;
+ }
UninstalledExtensionInfo uninstalled_extension_info(*extension);
@@ -667,6 +681,8 @@ void ExtensionService::UninstallExtension(const std::string& extension_id,
NotificationType::EXTENSION_UNINSTALLED,
Source<Profile>(profile_),
Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
+
+ return true;
}
void ExtensionService::ClearExtensionData(const GURL& extension_url) {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 54f70d6..344d323 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -60,8 +60,9 @@ class ExtensionServiceInterface {
virtual const Extension* GetExtensionById(const std::string& id,
bool include_disabled) const = 0;
- virtual void UninstallExtension(const std::string& extension_id,
- bool external_uninstall) = 0;
+ virtual bool UninstallExtension(const std::string& extension_id,
+ bool external_uninstall,
+ std::string* error) = 0;
virtual bool IsExtensionEnabled(const std::string& extension_id) const = 0;
virtual bool IsExternalExtensionUninstalled(
@@ -228,8 +229,9 @@ class ExtensionService
// callers should never set to true.
// TODO(aa): Remove |external_uninstall| -- this information should be passed
// to ExtensionPrefs some other way.
- virtual void UninstallExtension(const std::string& extension_id,
- bool external_uninstall);
+ virtual bool UninstallExtension(const std::string& extension_id,
+ bool external_uninstall,
+ std::string* error);
virtual bool IsExtensionEnabled(const std::string& extension_id) const;
virtual bool IsExternalExtensionUninstalled(
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index cae8b1b..d28eef5 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -1128,7 +1128,7 @@ TEST_F(ExtensionServiceTest, UninstallingExternalExtensions) {
ASSERT_TRUE(service_->GetExtensionById(good_crx, false));
// Uninstall it and check that its killbit gets set.
- service_->UninstallExtension(good_crx, false);
+ service_->UninstallExtension(good_crx, false, NULL);
loop_.RunAllPending();
ValidateIntegerPref(good_crx, "location",
Extension::EXTERNAL_EXTENSION_UNINSTALLED);
@@ -1789,7 +1789,7 @@ TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
// Uninstall one of them, unlimited storage should still be granted
// to the origin.
- service_->UninstallExtension(id1, false);
+ service_->UninstallExtension(id1, false, NULL);
loop_.RunAllPending();
EXPECT_EQ(1u, service_->extensions()->size());
EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()->
@@ -1797,7 +1797,7 @@ TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
// Uninstall the other, unlimited storage should be revoked.
- service_->UninstallExtension(id2, false);
+ service_->UninstallExtension(id2, false, NULL);
loop_.RunAllPending();
EXPECT_EQ(0u, service_->extensions()->size());
EXPECT_FALSE(profile_->GetExtensionSpecialStoragePolicy()->
@@ -1834,11 +1834,11 @@ TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) {
EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()->
IsStorageProtected(origin2));
- service_->UninstallExtension(id1, false);
+ service_->UninstallExtension(id1, false, NULL);
loop_.RunAllPending();
EXPECT_EQ(1u, service_->extensions()->size());
- service_->UninstallExtension(id2, false);
+ service_->UninstallExtension(id2, false, NULL);
loop_.RunAllPending();
EXPECT_TRUE(service_->extensions()->empty());
@@ -2702,7 +2702,7 @@ TEST_F(ExtensionServiceTest, UninstallExtension) {
ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
// Uninstall it.
- service_->UninstallExtension(extension_id, false);
+ service_->UninstallExtension(extension_id, false, NULL);
total_successes_ = 0;
// We should get an unload notification.
@@ -2819,7 +2819,7 @@ TEST_F(ExtensionServiceTest, ClearExtensionData) {
EXPECT_TRUE(file_util::PathExists(idb_path));
// Uninstall the extension.
- service_->UninstallExtension(good_crx, false);
+ service_->UninstallExtension(good_crx, false, NULL);
loop_.RunAllPending();
// Check that the cookie is gone.
@@ -2873,7 +2873,7 @@ TEST_F(ExtensionServiceTest, LoadExtension) {
// Test uninstall.
std::string id = loaded_[0]->id();
EXPECT_FALSE(unloaded_id_.length());
- service_->UninstallExtension(id, false);
+ service_->UninstallExtension(id, false, NULL);
loop_.RunAllPending();
EXPECT_EQ(id, unloaded_id_);
ASSERT_EQ(0u, loaded_.size());
@@ -2966,7 +2966,7 @@ void ExtensionServiceTest::TestExternalProvider(
// Uninstall the extension and reload. Nothing should happen because the
// preference should prevent us from reinstalling.
std::string id = loaded_[0]->id();
- service_->UninstallExtension(id, false);
+ service_->UninstallExtension(id, false, NULL);
loop_.RunAllPending();
FilePath install_path = extensions_install_dir_.AppendASCII(id);
@@ -3025,7 +3025,7 @@ void ExtensionServiceTest::TestExternalProvider(
// User uninstalls.
loaded_.clear();
- service_->UninstallExtension(id, false);
+ service_->UninstallExtension(id, false, NULL);
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc
index 16de5b4..e2f9b9f 100644
--- a/chrome/browser/extensions/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/extension_updater_unittest.cc
@@ -76,9 +76,11 @@ class MockService : public ExtensionServiceInterface {
return NULL;
}
- virtual void UninstallExtension(const std::string& extension_id,
- bool external_uninstall) {
- FAIL();
+ virtual bool UninstallExtension(const std::string& extension_id,
+ bool external_uninstall,
+ std::string* error) {
+ ADD_FAILURE();
+ return false;
}
virtual bool IsExtensionEnabled(const std::string& extension_id) const {
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 166c80c..ed29460 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -476,7 +476,7 @@ void ExtensionsDOMHandler::ExtensionDialogAccepted() {
return;
extensions_service_->UninstallExtension(extension_id_prompting_,
- false /* external_uninstall */);
+ false /* external_uninstall */, NULL);
extension_id_prompting_ = "";
// There will be no EXTENSION_UNLOADED notification for terminated
diff --git a/chrome/browser/sync/glue/extension_sync.cc b/chrome/browser/sync/glue/extension_sync.cc
index bef56cb..2834bb7 100644
--- a/chrome/browser/sync/glue/extension_sync.cc
+++ b/chrome/browser/sync/glue/extension_sync.cc
@@ -457,7 +457,7 @@ void RemoveFromClient(const ExtensionSyncTraits& traits,
const Extension* extension = extensions_service->GetExtensionById(id, true);
if (extension) {
if (traits.is_valid_and_syncable(*extension)) {
- extensions_service->UninstallExtension(id, false);
+ extensions_service->UninstallExtension(id, false, NULL);
} else {
LOG(WARNING) << "Ignoring server data for invalid or "
<< "non-syncable extension " << extension->id();
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 3c4c3ff..72a2dba 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -328,7 +328,7 @@ void ThemeService::RemoveUnusedThemes() {
}
}
for (size_t i = 0; i < remove_list.size(); ++i)
- service->UninstallExtension(remove_list[i], false);
+ service->UninstallExtension(remove_list[i], false, NULL);
}
void ThemeService::UseDefaultTheme() {
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm
index 3bf4cf4..989c472 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm
@@ -49,7 +49,7 @@ class AsyncUninstaller : public ExtensionUninstallDialog::Delegate {
// ExtensionUninstallDialog::Delegate:
virtual void ExtensionDialogAccepted() {
profile_->GetExtensionService()->
- UninstallExtension(extension_->id(), false);
+ UninstallExtension(extension_->id(), false, NULL);
}
virtual void ExtensionDialogCanceled() {}
diff --git a/chrome/browser/ui/webui/app_launcher_handler.cc b/chrome/browser/ui/webui/app_launcher_handler.cc
index 5cde49a..b71e113 100644
--- a/chrome/browser/ui/webui/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/app_launcher_handler.cc
@@ -559,7 +559,7 @@ void AppLauncherHandler::ExtensionDialogAccepted() {
return;
extensions_service_->UninstallExtension(extension_id_prompting_,
- false /* external_uninstall */);
+ false /* external_uninstall */, NULL);
extension_id_prompting_ = "";
}
@@ -617,6 +617,6 @@ void AppLauncherHandler::UninstallDefaultApps() {
for (ExtensionIdSet::const_iterator iter = app_ids.begin();
iter != app_ids.end(); ++iter) {
if (extensions_service_->GetExtensionById(*iter, true))
- extensions_service_->UninstallExtension(*iter, false);
+ extensions_service_->UninstallExtension(*iter, false, NULL);
}
}
diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc
index 0b612a6..1392671 100644
--- a/chrome/browser/ui/webui/options/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc
@@ -569,7 +569,7 @@ void ExtensionsDOMHandler::ExtensionDialogAccepted() {
return;
extensions_service_->UninstallExtension(extension_id_prompting_,
- false /* external_uninstall */);
+ false /* external_uninstall */, NULL);
extension_id_prompting_ = "";
// There will be no EXTENSION_UNLOADED notification for terminated
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 0facbf9..1f82e1c 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -108,6 +108,8 @@ const char* kCannotClaimAllURLsInExtent =
"Cannot claim all URLs in an extent.";
const char* kCannotScriptGallery =
"The extensions gallery cannot be scripted.";
+const char* kCannotUninstallManagedExtension =
+ "Attempted uninstallation of an extension that is not user-manageable.";
const char* kChromeVersionTooLow =
"This extension requires * version * or greater.";
const char* kDisabledByPolicy =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 3e8e130..3a09f9b 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -105,6 +105,7 @@ namespace extension_manifest_errors {
extern const char* kCannotClaimAllHostsInExtent;
extern const char* kCannotClaimAllURLsInExtent;
extern const char* kCannotScriptGallery;
+ extern const char* kCannotUninstallManagedExtension;
extern const char* kChromeVersionTooLow;
extern const char* kDevToolsExperimental;
extern const char* kDisabledByPolicy;
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index 85b1923..3f23800 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -245,6 +245,7 @@
'-https.HTTPSTest.testSSLPageBasic',
'-instant',
'-notifications',
+ '-ntp.NTPTest.testCannotUninstallWebStore',
'-ntp.NTPTest.testGetAppsInNewProfile',
'-ntp.NTPTest.testGetMenuModeInNewProfile',
'-ntp.NTPTest.testGetThumbnailModeInNewProfile',
diff --git a/chrome/test/functional/ntp.py b/chrome/test/functional/ntp.py
index e014613..23e8729 100644
--- a/chrome/test/functional/ntp.py
+++ b/chrome/test/functional/ntp.py
@@ -392,10 +392,26 @@ class NTPTest(pyauto.PyUITest):
self._VerifyAppInfo(app_info, expected_app_info)
# Next, uninstall the app and verify that it is removed from the NTP.
- self.UninstallApp(installed_app_id)
+ self.assertTrue(self.UninstallApp(installed_app_id),
+ msg='Call to UninstallApp() returned False.')
app_info = self.GetNTPApps()
self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS)
+ def testCannotUninstallWebStore(self):
+ """Ensures that the WebStore app cannot be uninstalled."""
+ # Verify that the WebStore app is already installed in a fresh profile.
+ app_info = self.GetNTPApps()
+ self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS)
+ self.assertTrue(app_info and 'id' in app_info[0],
+ msg='Cannot identify ID of WebStore app.')
+ webstore_id = app_info[0]['id']
+
+ # Attempt to uninstall the WebStore app and verify that it still exists
+ # in the App info of the NTP even after we try to uninstall it.
+ self.assertFalse(self.UninstallApp(webstore_id),
+ msg='Call to UninstallApp() returned True.')
+ self._VerifyAppInfo(self.GetNTPApps(), self._EXPECTED_DEFAULT_APPS)
+
def _VerifyThumbnailOrMenuMode(self, actual_info, expected_info):
"""Verifies that the expected thumbnail/menu info matches the actual info.
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index 10e0898..b868fde 100644
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -1227,12 +1227,16 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
Args:
id: The string id of the extension. It can be retrieved through the
GetExtensionsInfo call above.
+
+ Returns:
+ True, if the extension was successfully uninstalled, or
+ False, otherwise.
"""
cmd_dict = { # Prepare command for the json interface
'command': 'UninstallExtensionById',
- 'id': id
+ 'id': id,
}
- self._GetResultFromJSONRequest(cmd_dict)
+ return self._GetResultFromJSONRequest(cmd_dict)['success']
def SelectTranslateOption(self, option, tab_index=0, window_index=0):
"""Selects one of the options in the drop-down menu for the translate bar.
@@ -2196,6 +2200,10 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
Args:
app_id: The string ID of the app to uninstall. It can be retrieved
through the call to GetNTPApps above.
+
+ Returns:
+ True, if the app was successfully uninstalled, or
+ False, otherwise.
"""
return self.UninstallExtensionById(app_id)
diff --git a/content/common/notification_type.h b/content/common/notification_type.h
index e834e1d..f607640 100644
--- a/content/common/notification_type.h
+++ b/content/common/notification_type.h
@@ -888,6 +888,11 @@ class NotificationType {
// an UninstalledExtensionInfo struct and the source is a Profile.
EXTENSION_UNINSTALLED,
+ // Sent when an extension uninstall is not allowed because the extension is
+ // not user manageable. The details are an Extension, and the source is a
+ // Profile.
+ EXTENSION_UNINSTALL_NOT_ALLOWED,
+
// Sent when an extension is unloaded. This happens when an extension is
// uninstalled or disabled. The details are an UnloadedExtensionInfo, and
// the source is a Profile.