summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/extension_service.cc10
-rw-r--r--chrome/browser/extensions/extension_service.h9
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc42
-rw-r--r--chrome/browser/extensions/external_install_error.cc384
-rw-r--r--chrome/browser/extensions/external_install_error.h124
-rw-r--r--chrome/browser/extensions/external_install_manager.cc100
-rw-r--r--chrome/browser/extensions/external_install_manager.h78
-rw-r--r--chrome/browser/extensions/external_install_ui.cc590
-rw-r--r--chrome/browser/extensions/external_install_ui.h30
-rw-r--r--chrome/chrome_browser_extensions.gypi6
10 files changed, 728 insertions, 645 deletions
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 739f0a4..57818511 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -29,7 +29,7 @@
#include "chrome/browser/extensions/extension_special_storage_policy.h"
#include "chrome/browser/extensions/extension_sync_service.h"
#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/external_install_ui.h"
+#include "chrome/browser/extensions/external_install_manager.h"
#include "chrome/browser/extensions/external_provider_impl.h"
#include "chrome/browser/extensions/install_verifier.h"
#include "chrome/browser/extensions/installed_loader.h"
@@ -289,6 +289,8 @@ ExtensionService::ExtensionService(Profile* profile,
browser_terminating_(false),
installs_delayed_for_gc_(false),
is_first_run_(false),
+ external_install_manager_(
+ new extensions::ExternalInstallManager(profile_)),
shared_module_service_(new extensions::SharedModuleService(profile_)) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -1342,7 +1344,7 @@ void ExtensionService::UpdateExternalExtensionAlert() {
}
if (extension) {
- if (!extensions::HasExternalInstallError(this)) {
+ if (!external_install_manager_->HasExternalInstallError()) {
if (extension_prefs_->IncrementAcknowledgePromptCount(extension->id()) >
kMaxExtensionAcknowledgePromptCount) {
// Stop prompting for this extension, and check if there's another
@@ -1371,10 +1373,8 @@ void ExtensionService::UpdateExternalExtensionAlert() {
// (even if it's post-first run now).
bool first_run = extension_prefs_->IsExternalInstallFirstRun(
extension->id());
- extensions::AddExternalInstallError(this, extension, first_run);
+ external_install_manager_->AddExternalInstallError(extension, first_run);
}
- } else {
- extensions::RemoveExternalInstallError(this);
}
}
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 5159162..7342c2a 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -52,6 +52,7 @@ class ExtensionRegistry;
class ExtensionSystem;
class ExtensionUpdater;
class OneShotEvent;
+class ExternalInstallManager;
class SharedModuleService;
class UpdateObserver;
} // namespace extensions
@@ -387,6 +388,10 @@ class ExtensionService
return shared_module_service_.get();
}
+ extensions::ExternalInstallManager* external_install_manager() {
+ return external_install_manager_.get();
+ }
+
//////////////////////////////////////////////////////////////////////////////
// For Testing
@@ -676,6 +681,10 @@ class ExtensionService
// extensions.
scoped_ptr<extensions::ExtensionErrorController> error_controller_;
+ // The manager for extensions that were externally installed that is
+ // responsible for prompting the user about suspicious extensions.
+ scoped_ptr<extensions::ExternalInstallManager> external_install_manager_;
+
// Sequenced task runner for extension related file operations.
scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index da2e193..8b20087 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -47,7 +47,7 @@
#include "chrome/browser/extensions/extension_sync_data.h"
#include "chrome/browser/extensions/extension_sync_service.h"
#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/external_install_ui.h"
+#include "chrome/browser/extensions/external_install_manager.h"
#include "chrome/browser/extensions/external_policy_loader.h"
#include "chrome/browser/extensions/external_pref_loader.h"
#include "chrome/browser/extensions/external_provider_impl.h"
@@ -6743,7 +6743,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallGlobalError) {
service_->UpdateExternalExtensionAlert();
// Should return false, meaning there aren't any extensions that the user
// needs to know about.
- EXPECT_FALSE(extensions::HasExternalInstallError(service_));
+ EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError());
// This is a normal extension, installed normally.
// This should NOT trigger an alert.
@@ -6753,7 +6753,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallGlobalError) {
service_->CheckForExternalUpdates();
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(extensions::HasExternalInstallError(service_));
+ EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError());
// A hosted app, installed externally.
// This should NOT trigger an alert.
@@ -6765,7 +6765,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallGlobalError) {
content::NotificationService::AllSources());
service_->CheckForExternalUpdates();
observer.Wait();
- EXPECT_FALSE(extensions::HasExternalInstallError(service_));
+ EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError());
// Another normal extension, but installed externally.
// This SHOULD trigger an alert.
@@ -6777,7 +6777,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallGlobalError) {
content::NotificationService::AllSources());
service_->CheckForExternalUpdates();
observer2.Wait();
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
}
// Test that external extensions are initially disabled, and that enabling
@@ -6799,7 +6799,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallInitiallyDisabled) {
content::NotificationService::AllSources());
service_->CheckForExternalUpdates();
observer.Wait();
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
EXPECT_FALSE(service_->IsExtensionEnabled(page_action));
const Extension* extension =
@@ -6808,7 +6808,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallInitiallyDisabled) {
EXPECT_EQ(page_action, extension->id());
service_->EnableExtension(page_action);
- EXPECT_FALSE(extensions::HasExternalInstallError(service_));
+ EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError());
EXPECT_TRUE(service_->IsExtensionEnabled(page_action));
}
@@ -6841,20 +6841,25 @@ TEST_F(ExtensionServiceTest, MAYBE_ExternalInstallMultiple) {
base::Bind(&WaitForCountNotificationsCallback, &count));
service_->CheckForExternalUpdates();
observer.Wait();
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
EXPECT_FALSE(service_->IsExtensionEnabled(page_action));
EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
EXPECT_FALSE(service_->IsExtensionEnabled(theme_crx));
service_->EnableExtension(page_action);
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
- EXPECT_FALSE(extensions::HasExternalInstallBubble(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
+ EXPECT_FALSE(
+ service_->external_install_manager()->HasExternalInstallBubble());
+
service_->EnableExtension(theme_crx);
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
- EXPECT_FALSE(extensions::HasExternalInstallBubble(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
+ EXPECT_FALSE(
+ service_->external_install_manager()->HasExternalInstallBubble());
+
service_->EnableExtension(good_crx);
- EXPECT_FALSE(extensions::HasExternalInstallError(service_));
- EXPECT_FALSE(extensions::HasExternalInstallBubble(service_));
+ EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError());
+ EXPECT_FALSE(
+ service_->external_install_manager()->HasExternalInstallBubble());
}
// Test that there is a bubble for external extensions that update
@@ -6884,8 +6889,8 @@ TEST_F(ExtensionServiceTest, ExternalInstallUpdatesFromWebstoreOldProfile) {
content::NotificationService::AllSources());
service_->CheckForExternalUpdates();
observer.Wait();
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
- EXPECT_TRUE(extensions::HasExternalInstallBubble(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallBubble());
EXPECT_FALSE(service_->IsExtensionEnabled(updates_from_webstore));
}
@@ -6911,8 +6916,9 @@ TEST_F(ExtensionServiceTest, ExternalInstallUpdatesFromWebstoreNewProfile) {
content::NotificationService::AllSources());
service_->CheckForExternalUpdates();
observer.Wait();
- EXPECT_TRUE(extensions::HasExternalInstallError(service_));
- EXPECT_FALSE(extensions::HasExternalInstallBubble(service_));
+ EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError());
+ EXPECT_FALSE(
+ service_->external_install_manager()->HasExternalInstallBubble());
EXPECT_FALSE(service_->IsExtensionEnabled(updates_from_webstore));
}
diff --git a/chrome/browser/extensions/external_install_error.cc b/chrome/browser/extensions/external_install_error.cc
new file mode 100644
index 0000000..d8b7fbf
--- /dev/null
+++ b/chrome/browser/extensions/external_install_error.cc
@@ -0,0 +1,384 @@
+// Copyright 2014 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.
+
+#include "chrome/browser/extensions/external_install_error.h"
+
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/external_install_manager.h"
+#include "chrome/browser/extensions/webstore_data_fetcher.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/global_error/global_error.h"
+#include "chrome/browser/ui/global_error/global_error_service.h"
+#include "chrome/browser/ui/global_error/global_error_service_factory.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia_operations.h"
+
+namespace extensions {
+
+namespace {
+
+// Return the menu label for a global error.
+base::string16 GetMenuItemLabel(const Extension* extension) {
+ if (!extension)
+ return base::string16();
+
+ int id = -1;
+ if (extension->is_app())
+ id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
+ else if (extension->is_theme())
+ id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
+ else
+ id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
+
+ return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension->name()));
+}
+
+// A global error that spawns a dialog when the menu item is clicked.
+class ExternalInstallMenuAlert : public GlobalError {
+ public:
+ explicit ExternalInstallMenuAlert(ExternalInstallError* error);
+ virtual ~ExternalInstallMenuAlert();
+
+ private:
+ // GlobalError implementation.
+ virtual Severity GetSeverity() OVERRIDE;
+ virtual bool HasMenuItem() OVERRIDE;
+ virtual int MenuItemCommandID() OVERRIDE;
+ virtual base::string16 MenuItemLabel() OVERRIDE;
+ virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
+ virtual bool HasBubbleView() OVERRIDE;
+ virtual bool HasShownBubbleView() OVERRIDE;
+ virtual void ShowBubbleView(Browser* browser) OVERRIDE;
+ virtual GlobalErrorBubbleViewBase* GetBubbleView() OVERRIDE;
+
+ // The owning ExternalInstallError.
+ ExternalInstallError* error_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalInstallMenuAlert);
+};
+
+// A global error that spawns a bubble when the menu item is clicked.
+class ExternalInstallBubbleAlert : public GlobalErrorWithStandardBubble {
+ public:
+ explicit ExternalInstallBubbleAlert(ExternalInstallError* error,
+ ExtensionInstallPrompt::Prompt* prompt);
+ virtual ~ExternalInstallBubbleAlert();
+
+ private:
+ // GlobalError implementation.
+ virtual Severity GetSeverity() OVERRIDE;
+ virtual bool HasMenuItem() OVERRIDE;
+ virtual int MenuItemCommandID() OVERRIDE;
+ virtual base::string16 MenuItemLabel() OVERRIDE;
+ virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
+
+ // GlobalErrorWithStandardBubble implementation.
+ virtual gfx::Image GetBubbleViewIcon() OVERRIDE;
+ virtual base::string16 GetBubbleViewTitle() OVERRIDE;
+ virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
+ virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
+ virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
+ virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
+ virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
+ virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
+
+ // The owning ExternalInstallError.
+ ExternalInstallError* error_;
+
+ // The Prompt with all information, which we then use to populate the bubble.
+ ExtensionInstallPrompt::Prompt* prompt_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalInstallBubbleAlert);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ExternalInstallMenuAlert
+
+ExternalInstallMenuAlert::ExternalInstallMenuAlert(ExternalInstallError* error)
+ : error_(error) {
+}
+
+ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
+}
+
+GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
+ return SEVERITY_LOW;
+}
+
+bool ExternalInstallMenuAlert::HasMenuItem() {
+ return true;
+}
+
+int ExternalInstallMenuAlert::MenuItemCommandID() {
+ return IDC_EXTERNAL_EXTENSION_ALERT;
+}
+
+base::string16 ExternalInstallMenuAlert::MenuItemLabel() {
+ return GetMenuItemLabel(error_->GetExtension());
+}
+
+void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
+ error_->ShowDialog();
+}
+
+bool ExternalInstallMenuAlert::HasBubbleView() {
+ return false;
+}
+
+bool ExternalInstallMenuAlert::HasShownBubbleView() {
+ NOTREACHED();
+ return true;
+}
+
+void ExternalInstallMenuAlert::ShowBubbleView(Browser* browser) {
+ NOTREACHED();
+}
+
+GlobalErrorBubbleViewBase* ExternalInstallMenuAlert::GetBubbleView() {
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ExternalInstallBubbleAlert
+
+ExternalInstallBubbleAlert::ExternalInstallBubbleAlert(
+ ExternalInstallError* error,
+ ExtensionInstallPrompt::Prompt* prompt)
+ : error_(error),
+ prompt_(prompt) {
+ DCHECK(error_);
+ DCHECK(prompt_);
+}
+
+ExternalInstallBubbleAlert::~ExternalInstallBubbleAlert() {
+}
+
+GlobalError::Severity ExternalInstallBubbleAlert::GetSeverity() {
+ return SEVERITY_LOW;
+}
+
+bool ExternalInstallBubbleAlert::HasMenuItem() {
+ return true;
+}
+
+int ExternalInstallBubbleAlert::MenuItemCommandID() {
+ return IDC_EXTERNAL_EXTENSION_ALERT;
+}
+
+base::string16 ExternalInstallBubbleAlert::MenuItemLabel() {
+ return GetMenuItemLabel(error_->GetExtension());
+}
+
+void ExternalInstallBubbleAlert::ExecuteMenuItem(Browser* browser) {
+ ShowBubbleView(browser);
+}
+
+gfx::Image ExternalInstallBubbleAlert::GetBubbleViewIcon() {
+ if (prompt_->icon().IsEmpty())
+ return GlobalErrorWithStandardBubble::GetBubbleViewIcon();
+ // Scale icon to a reasonable size.
+ return gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
+ *prompt_->icon().ToImageSkia(),
+ skia::ImageOperations::RESIZE_BEST,
+ gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
+ extension_misc::EXTENSION_ICON_SMALL)));
+}
+
+base::string16 ExternalInstallBubbleAlert::GetBubbleViewTitle() {
+ return prompt_->GetDialogTitle();
+}
+
+std::vector<base::string16>
+ExternalInstallBubbleAlert::GetBubbleViewMessages() {
+ std::vector<base::string16> messages;
+ messages.push_back(prompt_->GetHeading());
+ if (prompt_->GetPermissionCount()) {
+ messages.push_back(prompt_->GetPermissionsHeading());
+ for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) {
+ messages.push_back(l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PERMISSION_LINE, prompt_->GetPermission(i)));
+ }
+ }
+ // TODO(yoz): OAuth issue advice?
+ return messages;
+}
+
+base::string16 ExternalInstallBubbleAlert::GetBubbleViewAcceptButtonLabel() {
+ return prompt_->GetAcceptButtonLabel();
+}
+
+base::string16 ExternalInstallBubbleAlert::GetBubbleViewCancelButtonLabel() {
+ return prompt_->GetAbortButtonLabel();
+}
+
+void ExternalInstallBubbleAlert::OnBubbleViewDidClose(Browser* browser) {
+}
+
+void ExternalInstallBubbleAlert::BubbleViewAcceptButtonPressed(
+ Browser* browser) {
+ error_->InstallUIProceed();
+}
+
+void ExternalInstallBubbleAlert::BubbleViewCancelButtonPressed(
+ Browser* browser) {
+ error_->InstallUIAbort(true);
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ExternalInstallError
+
+ExternalInstallError::ExternalInstallError(
+ content::BrowserContext* browser_context,
+ const std::string& extension_id,
+ AlertType alert_type,
+ ExternalInstallManager* manager)
+ : browser_context_(browser_context),
+ extension_id_(extension_id),
+ alert_type_(alert_type),
+ manager_(manager),
+ error_service_(GlobalErrorServiceFactory::GetForProfile(
+ Profile::FromBrowserContext(browser_context_))),
+ browser_(NULL),
+ weak_factory_(this) {
+#if !defined(OS_ANDROID)
+ browser_ =
+ chrome::FindTabbedBrowser(Profile::FromBrowserContext(browser_context_),
+ true,
+ chrome::GetActiveDesktop());
+#endif
+
+ prompt_.reset(new ExtensionInstallPrompt::Prompt(
+ ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT));
+
+ webstore_data_fetcher_.reset(new WebstoreDataFetcher(
+ this, browser_context_->GetRequestContext(), GURL(), extension_id_));
+ webstore_data_fetcher_->Start();
+}
+
+ExternalInstallError::~ExternalInstallError() {
+ if (global_error_.get())
+ error_service_->RemoveGlobalError(global_error_.get());
+}
+
+void ExternalInstallError::InstallUIProceed() {
+ const Extension* extension = GetExtension();
+ if (extension) {
+ ExtensionSystem::Get(browser_context_)
+ ->extension_service()
+ ->GrantPermissionsAndEnableExtension(extension);
+ }
+ manager_->RemoveExternalInstallError();
+}
+
+void ExternalInstallError::InstallUIAbort(bool user_initiated) {
+ if (user_initiated && GetExtension()) {
+ ExtensionSystem::Get(browser_context_)
+ ->extension_service()
+ ->UninstallExtension(extension_id_,
+ false, // Not externally uninstalled.
+ NULL); // Ignore error.
+ }
+ manager_->RemoveExternalInstallError();
+}
+
+void ExternalInstallError::AcknowledgeExtension() {
+ const Extension* extension = GetExtension();
+ if (extension) {
+ ExtensionSystem::Get(browser_context_)
+ ->extension_service()
+ ->AcknowledgeExternalExtension(extension->id());
+ }
+}
+
+void ExternalInstallError::ShowDialog() {
+ DCHECK(install_ui_.get());
+ DCHECK(prompt_.get());
+ DCHECK(show_params_.get());
+ ExtensionInstallPrompt::GetDefaultShowDialogCallback().Run(
+ *show_params_, this, *prompt_);
+}
+
+const Extension* ExternalInstallError::GetExtension() const {
+ return ExtensionRegistry::Get(browser_context_)
+ ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
+}
+
+void ExternalInstallError::OnWebstoreRequestFailure() {
+ OnFetchComplete();
+}
+
+void ExternalInstallError::OnWebstoreResponseParseSuccess(
+ scoped_ptr<base::DictionaryValue> webstore_data) {
+ std::string localized_user_count;
+ double average_rating;
+ int rating_count;
+ if (!webstore_data->GetString(kUsersKey, &localized_user_count) ||
+ !webstore_data->GetDouble(kAverageRatingKey, &average_rating) ||
+ !webstore_data->GetInteger(kRatingCountKey, &rating_count)) {
+ // If we don't get a valid webstore response, short circuit, and continue
+ // to show a prompt without webstore data.
+ OnFetchComplete();
+ return;
+ }
+
+ bool show_user_count = true;
+ webstore_data->GetBoolean(kShowUserCountKey, &show_user_count);
+
+ prompt_->SetWebstoreData(
+ localized_user_count, show_user_count, average_rating, rating_count);
+ OnFetchComplete();
+}
+
+void ExternalInstallError::OnWebstoreResponseParseFailure(
+ const std::string& error) {
+ OnFetchComplete();
+}
+
+void ExternalInstallError::OnFetchComplete() {
+ install_ui_.reset(
+ ExtensionInstallUI::CreateInstallPromptWithBrowser(browser_));
+
+ install_ui_->ConfirmExternalInstall(
+ this,
+ GetExtension(),
+ base::Bind(&ExternalInstallError::OnDialogReady,
+ weak_factory_.GetWeakPtr()),
+ *prompt_);
+}
+
+void ExternalInstallError::OnDialogReady(
+ const ExtensionInstallPrompt::ShowParams& show_params,
+ ExtensionInstallPrompt::Delegate* prompt_delegate,
+ const ExtensionInstallPrompt::Prompt& prompt) {
+ DCHECK_EQ(this, prompt_delegate);
+ show_params_.reset(new ExtensionInstallPrompt::ShowParams(show_params));
+ prompt_.reset(new ExtensionInstallPrompt::Prompt(prompt));
+
+ if (alert_type_ == BUBBLE_ALERT) {
+ global_error_.reset(new ExternalInstallBubbleAlert(this, prompt_.get()));
+ error_service_->AddGlobalError(global_error_.get());
+ if (browser_)
+ global_error_->ShowBubbleView(browser_);
+ } else {
+ DCHECK(alert_type_ == MENU_ALERT);
+ global_error_.reset(new ExternalInstallMenuAlert(this));
+ error_service_->AddGlobalError(global_error_.get());
+ }
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/external_install_error.h b/chrome/browser/extensions/external_install_error.h
new file mode 100644
index 0000000..aa53afc
--- /dev/null
+++ b/chrome/browser/extensions/external_install_error.h
@@ -0,0 +1,124 @@
+// Copyright 2014 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_ERROR_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_ERROR_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/extensions/extension_install_prompt.h"
+#include "chrome/browser/extensions/webstore_data_fetcher_delegate.h"
+
+class ExtensionInstallUI;
+class GlobalError;
+class GlobalErrorService;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+class Extension;
+class ExternalInstallManager;
+class WebstoreDataFetcher;
+
+// An error to show the user an extension has been externally installed. The
+// error will automatically fetch data about the extension from the webstore (if
+// possible) and will handle adding itself to the GlobalErrorService when
+// initialized and removing itself from the GlobalErrorService upon
+// destruction.
+class ExternalInstallError : public ExtensionInstallPrompt::Delegate,
+ public WebstoreDataFetcherDelegate {
+ public:
+ // The possible types of errors to show. A menu alert adds a menu item to the
+ // wrench, which spawns an extension install dialog when clicked. The bubble
+ // alert also adds an item, but spawns a bubble instead (less invasive and
+ // easier to dismiss).
+ enum AlertType {
+ BUBBLE_ALERT,
+ MENU_ALERT
+ };
+
+ ExternalInstallError(content::BrowserContext* browser_context,
+ const std::string& extension_id,
+ AlertType error_type,
+ ExternalInstallManager* manager);
+ virtual ~ExternalInstallError();
+
+ // ExtensionInstallPrompt::Delegate implementation.
+ virtual void InstallUIProceed() OVERRIDE;
+ virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
+
+ // Acknowledge the associated external extension.
+ void AcknowledgeExtension();
+
+ // Show the associated dialog. This should only be called once the dialog is
+ // ready.
+ void ShowDialog();
+
+ // Return the associated extension, or NULL.
+ const Extension* GetExtension() const;
+
+ const std::string& extension_id() const { return extension_id_; }
+ AlertType alert_type() const { return alert_type_; }
+
+ private:
+ // WebstoreDataFetcherDelegate implementation.
+ virtual void OnWebstoreRequestFailure() OVERRIDE;
+ virtual void OnWebstoreResponseParseSuccess(
+ scoped_ptr<base::DictionaryValue> webstore_data) OVERRIDE;
+ virtual void OnWebstoreResponseParseFailure(
+ const std::string& error) OVERRIDE;
+
+ // Called when data fetching has completed (either successfully or not).
+ void OnFetchComplete();
+
+ // Called when the dialog has been successfully populated, and is ready to be
+ // shown.
+ void OnDialogReady(const ExtensionInstallPrompt::ShowParams& show_params,
+ ExtensionInstallPrompt::Delegate* prompt_delegate,
+ const ExtensionInstallPrompt::Prompt& prompt);
+
+ // The associated BrowserContext.
+ content::BrowserContext* browser_context_;
+
+ // The id of the external extension.
+ std::string extension_id_;
+
+ // The type of alert to show the user.
+ AlertType alert_type_;
+
+ // The owning ExternalInstallManager.
+ ExternalInstallManager* manager_;
+
+ // The associated GlobalErrorService.
+ GlobalErrorService* error_service_;
+
+ // The UI for showing the error.
+ scoped_ptr<ExtensionInstallPrompt> install_ui_;
+ scoped_ptr<ExtensionInstallPrompt::Prompt> prompt_;
+ scoped_ptr<ExtensionInstallPrompt::ShowParams> show_params_;
+
+ // The UI for the given error, which will take the form of either a menu
+ // alert or a bubble alert (depending on the |alert_type_|.
+ scoped_ptr<GlobalError> global_error_;
+
+ // The associated browser. Can be NULL.
+ Browser* browser_;
+
+ // The WebstoreDataFetcher to use in order to populate the error with webstore
+ // information of the extension.
+ scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher_;
+
+ base::WeakPtrFactory<ExternalInstallError> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalInstallError);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_ERROR_H_
diff --git a/chrome/browser/extensions/external_install_manager.cc b/chrome/browser/extensions/external_install_manager.cc
new file mode 100644
index 0000000..0dbbb1c
--- /dev/null
+++ b/chrome/browser/extensions/external_install_manager.cc
@@ -0,0 +1,100 @@
+// Copyright 2014 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.
+
+#include "chrome/browser/extensions/external_install_manager.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/external_install_error.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/manifest_url_handler.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+
+ExternalInstallManager::ExternalInstallManager(
+ content::BrowserContext* browser_context)
+ : browser_context_(browser_context),
+ extension_registry_observer_(this) {
+ DCHECK(browser_context_);
+ extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSION_REMOVED,
+ content::Source<Profile>(
+ Profile::FromBrowserContext(browser_context_)));
+}
+
+ExternalInstallManager::~ExternalInstallManager() {
+}
+
+void ExternalInstallManager::AddExternalInstallError(const Extension* extension,
+ bool is_new_profile) {
+ if (HasExternalInstallError())
+ return; // Only have one external install error at a time.
+
+ if (ManifestURL::UpdatesFromGallery(extension) && !is_new_profile) {
+ error_.reset(new ExternalInstallError(browser_context_,
+ extension->id(),
+ ExternalInstallError::BUBBLE_ALERT,
+ this));
+ } else {
+ error_.reset(new ExternalInstallError(browser_context_,
+ extension->id(),
+ ExternalInstallError::MENU_ALERT,
+ this));
+ }
+}
+
+void ExternalInstallManager::RemoveExternalInstallError() {
+ error_.reset();
+ ExtensionSystem::Get(browser_context_)
+ ->extension_service()
+ ->UpdateExternalExtensionAlert();
+}
+
+bool ExternalInstallManager::HasExternalInstallError() const {
+ return error_.get() != NULL;
+}
+
+bool ExternalInstallManager::HasExternalInstallBubble() const {
+ return error_.get() &&
+ error_->alert_type() == ExternalInstallError::BUBBLE_ALERT;
+}
+
+void ExternalInstallManager::OnExtensionLoaded(
+ content::BrowserContext* browser_context,
+ const Extension* extension) {
+ // The error is invalidated if the extension has been loaded or removed.
+ if (error_.get() && extension->id() == error_->extension_id()) {
+ // We treat loading as acknowledgement (since the user consciously chose to
+ // re-enable the extension).
+ error_->AcknowledgeExtension();
+ RemoveExternalInstallError();
+ }
+}
+
+void ExternalInstallManager::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_REMOVED, type);
+ // The error is invalidated if the extension has been loaded or removed.
+ // It's a shame we have to use the notification system (instead of the
+ // registry observer) for this, but the ExtensionUnloaded notification is
+ // not sent out if the extension is disabled (which it is here).
+ if (error_.get() &&
+ content::Details<const Extension>(details).ptr()->id() ==
+ error_->extension_id()) {
+ RemoveExternalInstallError();
+ }
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/external_install_manager.h b/chrome/browser/extensions/external_install_manager.h
new file mode 100644
index 0000000..0cfb306
--- /dev/null
+++ b/chrome/browser/extensions/external_install_manager.h
@@ -0,0 +1,78 @@
+// Copyright 2014 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_MANAGER_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/scoped_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/extension_registry_observer.h"
+
+class GlobalErrorService;
+
+namespace content {
+class BrowserContext;
+class NotificationDetails;
+class NotificationSource;
+}
+
+namespace extensions {
+class Extension;
+class ExtensionRegistry;
+class ExternalInstallError;
+
+class ExternalInstallManager : public ExtensionRegistryObserver,
+ public content::NotificationObserver {
+ public:
+ explicit ExternalInstallManager(content::BrowserContext* browser_context);
+ virtual ~ExternalInstallManager();
+
+ // Adds a global error informing the user that an external extension was
+ // installed. If |is_new_profile| is true, then this error is from the first
+ // time our profile checked for new extensions.
+ void AddExternalInstallError(const Extension* extension, bool is_new_profile);
+
+ // Removes the global error, if one existed.
+ void RemoveExternalInstallError();
+
+ // Returns true if there is a global error for an external install.
+ bool HasExternalInstallError() const;
+
+ // Returns true if there is a global error with a bubble view for an external
+ // install. Used for testing.
+ bool HasExternalInstallBubble() const;
+
+ // Returns the current install error, if one exists.
+ const ExternalInstallError* error() { return error_.get(); }
+
+ private:
+ // ExtensionRegistryObserver implementation.
+ virtual void OnExtensionLoaded(content::BrowserContext* browser_context,
+ const Extension* extension) OVERRIDE;
+
+ // content::NotificationObserver implementation.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // The associated BrowserContext.
+ content::BrowserContext* browser_context_;
+
+ // The current ExternalInstallError, if one exists.
+ scoped_ptr<ExternalInstallError> error_;
+
+ content::NotificationRegistrar registrar_;
+
+ ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
+ extension_registry_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalInstallManager);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_MANAGER_H_
diff --git a/chrome/browser/extensions/external_install_ui.cc b/chrome/browser/extensions/external_install_ui.cc
deleted file mode 100644
index 0f786468a00..0000000
--- a/chrome/browser/extensions/external_install_ui.cc
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright (c) 2012 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.
-
-#include "chrome/browser/extensions/external_install_ui.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "base/scoped_observer.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
-#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_uninstall_dialog.h"
-#include "chrome/browser/extensions/webstore_data_fetcher.h"
-#include "chrome/browser/extensions/webstore_data_fetcher_delegate.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/global_error/global_error.h"
-#include "chrome/browser/ui/global_error/global_error_service.h"
-#include "chrome/browser/ui/global_error/global_error_service_factory.h"
-#include "chrome/common/extensions/manifest_url_handler.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_registry_observer.h"
-#include "extensions/common/constants.h"
-#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia_operations.h"
-
-namespace extensions {
-
-namespace {
-
-// Whether the external extension can use the streamlined bubble install flow.
-bool UseBubbleInstall(const Extension* extension, bool is_new_profile) {
- return ManifestURL::UpdatesFromGallery(extension) && !is_new_profile;
-}
-
-} // namespace
-
-static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT;
-
-class ExternalInstallGlobalError;
-
-namespace extensions {
-class ExtensionRegistry;
-}
-
-// This class is refcounted to stay alive while we try and pull webstore data.
-class ExternalInstallDialogDelegate
- : public ExtensionInstallPrompt::Delegate,
- public WebstoreDataFetcherDelegate,
- public content::NotificationObserver,
- public base::RefCountedThreadSafe<ExternalInstallDialogDelegate> {
- public:
- ExternalInstallDialogDelegate(Browser* browser,
- ExtensionService* service,
- const Extension* extension,
- bool use_global_error);
-
- Browser* browser() { return browser_; }
-
- private:
- friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>;
- friend class ExternalInstallGlobalError;
-
- virtual ~ExternalInstallDialogDelegate();
-
- // ExtensionInstallPrompt::Delegate:
- virtual void InstallUIProceed() OVERRIDE;
- virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
-
- // WebstoreDataFetcherDelegate:
- virtual void OnWebstoreRequestFailure() OVERRIDE;
- virtual void OnWebstoreResponseParseSuccess(
- scoped_ptr<base::DictionaryValue> webstore_data) OVERRIDE;
- virtual void OnWebstoreResponseParseFailure(
- const std::string& error) OVERRIDE;
-
- // content::NotificationObserver:
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
- // Show the install dialog to the user.
- void ShowInstallUI();
-
- // The UI for showing the install dialog when enabling.
- scoped_ptr<ExtensionInstallPrompt> install_ui_;
- scoped_ptr<ExtensionInstallPrompt::Prompt> prompt_;
-
- Browser* browser_;
- base::WeakPtr<ExtensionService> service_weak_;
- scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher_;
- content::NotificationRegistrar registrar_;
- std::string extension_id_;
- bool use_global_error_;
-
- DISALLOW_COPY_AND_ASSIGN(ExternalInstallDialogDelegate);
-};
-
-// Only shows a menu item, no bubble. Clicking the menu item shows
-// an external install dialog.
-class ExternalInstallMenuAlert : public GlobalErrorWithStandardBubble,
- public content::NotificationObserver,
- public ExtensionRegistryObserver {
- public:
- ExternalInstallMenuAlert(ExtensionService* service,
- const Extension* extension);
- virtual ~ExternalInstallMenuAlert();
-
- // GlobalError implementation.
- virtual Severity GetSeverity() OVERRIDE;
- virtual bool HasMenuItem() OVERRIDE;
- virtual int MenuItemCommandID() OVERRIDE;
- virtual base::string16 MenuItemLabel() OVERRIDE;
- virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
- virtual bool HasBubbleView() OVERRIDE;
- virtual base::string16 GetBubbleViewTitle() OVERRIDE;
- virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
- virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
- virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
- virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
- virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
- virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
-
- protected:
- ExtensionService* service_;
- const Extension* extension_;
-
- private:
- // Delete this instance after cleaning jobs.
- void Clean();
-
- // content::NotificationObserver implementation.
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
- // ExtensionRegistryObserver implementation.
- virtual void OnExtensionLoaded(content::BrowserContext* browser_context,
- const Extension* extension) OVERRIDE;
-
- content::NotificationRegistrar registrar_;
-
- // Listen to extension load notifications.
- ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
- extension_registry_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(ExternalInstallMenuAlert);
-};
-
-// Shows a menu item and a global error bubble, replacing the install dialog.
-class ExternalInstallGlobalError : public ExternalInstallMenuAlert {
- public:
- ExternalInstallGlobalError(ExtensionService* service,
- const Extension* extension,
- ExternalInstallDialogDelegate* delegate,
- const ExtensionInstallPrompt::Prompt& prompt);
- virtual ~ExternalInstallGlobalError();
-
- virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
- virtual bool HasBubbleView() OVERRIDE;
- virtual gfx::Image GetBubbleViewIcon() OVERRIDE;
- virtual base::string16 GetBubbleViewTitle() OVERRIDE;
- virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
- virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
- virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
- virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
- virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
- virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
-
- protected:
- // Ref-counted, but needs to be disposed of if we are dismissed without
- // having been clicked (perhaps because the user enabled the extension
- // manually).
- ExternalInstallDialogDelegate* delegate_;
- const ExtensionInstallPrompt::Prompt* prompt_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ExternalInstallGlobalError);
-};
-
-static void CreateExternalInstallGlobalError(
- base::WeakPtr<ExtensionService> service,
- const std::string& extension_id,
- const ExtensionInstallPrompt::ShowParams& show_params,
- ExtensionInstallPrompt::Delegate* prompt_delegate,
- const ExtensionInstallPrompt::Prompt& prompt) {
- if (!service.get())
- return;
- const Extension* extension = service->GetInstalledExtension(extension_id);
- if (!extension)
- return;
- GlobalErrorService* error_service =
- GlobalErrorServiceFactory::GetForProfile(service->profile());
- if (error_service->GetGlobalErrorByMenuItemCommandID(kMenuCommandId))
- return;
-
- ExternalInstallDialogDelegate* delegate =
- static_cast<ExternalInstallDialogDelegate*>(prompt_delegate);
- ExternalInstallGlobalError* error_bubble = new ExternalInstallGlobalError(
- service.get(), extension, delegate, prompt);
- error_service->AddGlobalError(error_bubble);
- // Show bubble immediately if possible.
- if (delegate->browser())
- error_bubble->ShowBubbleView(delegate->browser());
-}
-
-static void ShowExternalInstallDialog(
- ExtensionService* service,
- Browser* browser,
- const Extension* extension) {
- // This object manages its own lifetime.
- new ExternalInstallDialogDelegate(browser, service, extension, false);
-}
-
-// ExternalInstallDialogDelegate --------------------------------------------
-
-ExternalInstallDialogDelegate::ExternalInstallDialogDelegate(
- Browser* browser,
- ExtensionService* service,
- const Extension* extension,
- bool use_global_error)
- : browser_(browser),
- service_weak_(service->AsWeakPtr()),
- extension_id_(extension->id()),
- use_global_error_(use_global_error) {
- AddRef(); // Balanced in Proceed or Abort.
-
- prompt_.reset(new ExtensionInstallPrompt::Prompt(
- ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT));
-
- // If we don't have a browser, we can't go to the webstore to fetch data.
- // This should only happen in tests.
- if (!browser) {
- ShowInstallUI();
- return;
- }
-
- // Make sure to be notified if the owning profile is destroyed.
- registrar_.Add(this,
- chrome::NOTIFICATION_PROFILE_DESTROYED,
- content::Source<Profile>(browser->profile()));
-
- webstore_data_fetcher_.reset(new WebstoreDataFetcher(
- this,
- browser->profile()->GetRequestContext(),
- GURL::EmptyGURL(),
- extension->id()));
- webstore_data_fetcher_->Start();
-}
-
-void ExternalInstallDialogDelegate::OnWebstoreRequestFailure() {
- ShowInstallUI();
-}
-
-void ExternalInstallDialogDelegate::OnWebstoreResponseParseSuccess(
- scoped_ptr<base::DictionaryValue> webstore_data) {
- std::string localized_user_count;
- double average_rating;
- int rating_count;
- if (!webstore_data->GetString(kUsersKey, &localized_user_count) ||
- !webstore_data->GetDouble(kAverageRatingKey, &average_rating) ||
- !webstore_data->GetInteger(kRatingCountKey, &rating_count)) {
- // If we don't get a valid webstore response, short circuit, and continue
- // to show a prompt without webstore data.
- ShowInstallUI();
- return;
- }
-
- bool show_user_count = true;
- webstore_data->GetBoolean(kShowUserCountKey, &show_user_count);
-
- prompt_->SetWebstoreData(localized_user_count,
- show_user_count,
- average_rating,
- rating_count);
-
- ShowInstallUI();
-}
-
-void ExternalInstallDialogDelegate::OnWebstoreResponseParseFailure(
- const std::string& error) {
- ShowInstallUI();
-}
-
-void ExternalInstallDialogDelegate::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_DESTROYED);
- // If the owning profile is destroyed, we need to abort so that we don't leak.
- InstallUIAbort(false); // Not user initiated.
-}
-
-void ExternalInstallDialogDelegate::ShowInstallUI() {
- const Extension* extension = NULL;
- if (!service_weak_.get() ||
- !(extension = service_weak_->GetInstalledExtension(extension_id_))) {
- return;
- }
- install_ui_.reset(
- ExtensionInstallUI::CreateInstallPromptWithBrowser(browser_));
-
- const ExtensionInstallPrompt::ShowDialogCallback callback =
- use_global_error_ ?
- base::Bind(&CreateExternalInstallGlobalError,
- service_weak_,
- extension_id_) :
- ExtensionInstallPrompt::GetDefaultShowDialogCallback();
-
- install_ui_->ConfirmExternalInstall(this, extension, callback, *prompt_);
-}
-
-ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() {
-}
-
-void ExternalInstallDialogDelegate::InstallUIProceed() {
- const Extension* extension = NULL;
- if (service_weak_.get() &&
- (extension = service_weak_->GetInstalledExtension(extension_id_))) {
- service_weak_->GrantPermissionsAndEnableExtension(extension);
- }
- Release();
-}
-
-void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) {
- const Extension* extension = NULL;
-
- // Uninstall the extension if the abort was user initiated (and not, e.g., the
- // result of the window closing).
- // Otherwise, the extension will remain installed, but unacknowledged, so it
- // will be prompted again.
- if (user_initiated &&
- service_weak_.get() &&
- (extension = service_weak_->GetInstalledExtension(extension_id_))) {
- service_weak_->UninstallExtension(extension_id_, false, NULL);
- }
- Release();
-}
-
-// ExternalInstallMenuAlert -------------------------------------------------
-
-ExternalInstallMenuAlert::ExternalInstallMenuAlert(ExtensionService* service,
- const Extension* extension)
- : service_(service),
- extension_(extension),
- extension_registry_observer_(this) {
- extension_registry_observer_.Add(ExtensionRegistry::Get(service->profile()));
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_REMOVED,
- content::Source<Profile>(service->profile()));
-}
-
-ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
-}
-
-GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
- return SEVERITY_LOW;
-}
-
-bool ExternalInstallMenuAlert::HasMenuItem() {
- return true;
-}
-
-int ExternalInstallMenuAlert::MenuItemCommandID() {
- return kMenuCommandId;
-}
-
-base::string16 ExternalInstallMenuAlert::MenuItemLabel() {
- int id = -1;
- if (extension_->is_app())
- id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
- else if (extension_->is_theme())
- id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
- else
- id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
- return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name()));
-}
-
-void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
- ShowExternalInstallDialog(service_, browser, extension_);
-}
-
-bool ExternalInstallMenuAlert::HasBubbleView() {
- return false;
-}
-base::string16 ExternalInstallMenuAlert::GetBubbleViewTitle() {
- return base::string16();
-}
-
-std::vector<base::string16> ExternalInstallMenuAlert::GetBubbleViewMessages() {
- return std::vector<base::string16>();
-}
-
-base::string16 ExternalInstallMenuAlert::GetBubbleViewAcceptButtonLabel() {
- return base::string16();
-}
-
-base::string16 ExternalInstallMenuAlert::GetBubbleViewCancelButtonLabel() {
- return base::string16();
-}
-
-void ExternalInstallMenuAlert::OnBubbleViewDidClose(Browser* browser) {
- NOTREACHED();
-}
-
-void ExternalInstallMenuAlert::BubbleViewAcceptButtonPressed(
- Browser* browser) {
- NOTREACHED();
-}
-
-void ExternalInstallMenuAlert::BubbleViewCancelButtonPressed(
- Browser* browser) {
- NOTREACHED();
-}
-
-void ExternalInstallMenuAlert::OnExtensionLoaded(
- content::BrowserContext* browser_context,
- const Extension* extension) {
- if (extension == extension_)
- Clean();
-}
-
-void ExternalInstallMenuAlert::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- // The error is invalidated if the extension has been loaded or removed.
- DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_REMOVED);
- const Extension* extension = content::Details<const Extension>(details).ptr();
- if (extension == extension_)
- Clean();
-}
-
-void ExternalInstallMenuAlert::Clean() {
- GlobalErrorService* error_service =
- GlobalErrorServiceFactory::GetForProfile(service_->profile());
- error_service->RemoveGlobalError(this);
- service_->AcknowledgeExternalExtension(extension_->id());
- delete this;
-}
-
-// ExternalInstallGlobalError -----------------------------------------------
-
-ExternalInstallGlobalError::ExternalInstallGlobalError(
- ExtensionService* service,
- const Extension* extension,
- ExternalInstallDialogDelegate* delegate,
- const ExtensionInstallPrompt::Prompt& prompt)
- : ExternalInstallMenuAlert(service, extension),
- delegate_(delegate),
- prompt_(&prompt) {
-}
-
-ExternalInstallGlobalError::~ExternalInstallGlobalError() {
- if (delegate_)
- delegate_->Release();
-}
-
-void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) {
- ShowBubbleView(browser);
-}
-
-bool ExternalInstallGlobalError::HasBubbleView() {
- return true;
-}
-
-gfx::Image ExternalInstallGlobalError::GetBubbleViewIcon() {
- if (prompt_->icon().IsEmpty())
- return GlobalErrorWithStandardBubble::GetBubbleViewIcon();
- // Scale icon to a reasonable size.
- return gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
- *prompt_->icon().ToImageSkia(),
- skia::ImageOperations::RESIZE_BEST,
- gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
- extension_misc::EXTENSION_ICON_SMALL)));
-}
-
-base::string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
- return prompt_->GetDialogTitle();
-}
-
-std::vector<base::string16>
-ExternalInstallGlobalError::GetBubbleViewMessages() {
- std::vector<base::string16> messages;
- messages.push_back(prompt_->GetHeading());
- if (prompt_->GetPermissionCount()) {
- messages.push_back(prompt_->GetPermissionsHeading());
- for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) {
- messages.push_back(l10n_util::GetStringFUTF16(
- IDS_EXTENSION_PERMISSION_LINE,
- prompt_->GetPermission(i)));
- }
- }
- // TODO(yoz): OAuth issue advice?
- return messages;
-}
-
-base::string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() {
- return prompt_->GetAcceptButtonLabel();
-}
-
-base::string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() {
- return prompt_->GetAbortButtonLabel();
-}
-
-void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) {
-}
-
-void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed(
- Browser* browser) {
- ExternalInstallDialogDelegate* delegate = delegate_;
- delegate_ = NULL;
- delegate->InstallUIProceed();
-}
-
-void ExternalInstallGlobalError::BubbleViewCancelButtonPressed(
- Browser* browser) {
- ExternalInstallDialogDelegate* delegate = delegate_;
- delegate_ = NULL;
- delegate->InstallUIAbort(true);
-}
-
-// Public interface ---------------------------------------------------------
-
-void AddExternalInstallError(ExtensionService* service,
- const Extension* extension,
- bool is_new_profile) {
- GlobalErrorService* error_service =
- GlobalErrorServiceFactory::GetForProfile(service->profile());
- if (error_service->GetGlobalErrorByMenuItemCommandID(kMenuCommandId))
- return;
-
- if (UseBubbleInstall(extension, is_new_profile)) {
- Browser* browser = NULL;
-#if !defined(OS_ANDROID)
- browser = chrome::FindTabbedBrowser(service->profile(),
- true,
- chrome::GetActiveDesktop());
-#endif
- new ExternalInstallDialogDelegate(browser, service, extension, true);
- } else {
- error_service->AddGlobalError(
- new ExternalInstallMenuAlert(service, extension));
- }
-}
-
-void RemoveExternalInstallError(ExtensionService* service) {
- GlobalErrorService* error_service =
- GlobalErrorServiceFactory::GetForProfile(service->profile());
- GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
- kMenuCommandId);
- if (error) {
- error_service->RemoveGlobalError(error);
- delete error;
- }
-}
-
-bool HasExternalInstallError(ExtensionService* service) {
- GlobalErrorService* error_service =
- GlobalErrorServiceFactory::GetForProfile(service->profile());
- GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
- kMenuCommandId);
- return !!error;
-}
-
-bool HasExternalInstallBubble(ExtensionService* service) {
- GlobalErrorService* error_service =
- GlobalErrorServiceFactory::GetForProfile(service->profile());
- GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
- kMenuCommandId);
- return error && error->HasBubbleView();
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/external_install_ui.h b/chrome/browser/extensions/external_install_ui.h
deleted file mode 100644
index b8ee953..0000000
--- a/chrome/browser/extensions/external_install_ui.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_UI_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_UI_H_
-
-class Browser;
-class ExtensionService;
-
-namespace extensions {
-
-class Extension;
-
-// Adds/Removes a global error informing the user that an external extension
-// was installed. If |is_new_profile| is true, then this error is from the
-// first time our profile checked for new external extensions.
-void AddExternalInstallError(ExtensionService* service,
- const Extension* extension,
- bool is_new_profile);
-void RemoveExternalInstallError(ExtensionService* service);
-
-bool HasExternalInstallError(ExtensionService* service);
-
-// Used for testing.
-bool HasExternalInstallBubble(ExtensionService* service);
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_UI_H_
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 4e527d5..0b0d070 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -800,8 +800,10 @@
'browser/extensions/extension_webkit_preferences.h',
'browser/extensions/external_component_loader.cc',
'browser/extensions/external_component_loader.h',
- 'browser/extensions/external_install_ui.cc',
- 'browser/extensions/external_install_ui.h',
+ 'browser/extensions/external_install_error.cc',
+ 'browser/extensions/external_install_error.h',
+ 'browser/extensions/external_install_manager.cc',
+ 'browser/extensions/external_install_manager.h',
'browser/extensions/external_loader.cc',
'browser/extensions/external_loader.h',
'browser/extensions/external_policy_loader.cc',