diff options
-rw-r--r-- | chrome/browser/extensions/extension_service.cc | 10 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.h | 9 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service_unittest.cc | 42 | ||||
-rw-r--r-- | chrome/browser/extensions/external_install_error.cc | 384 | ||||
-rw-r--r-- | chrome/browser/extensions/external_install_error.h | 124 | ||||
-rw-r--r-- | chrome/browser/extensions/external_install_manager.cc | 100 | ||||
-rw-r--r-- | chrome/browser/extensions/external_install_manager.h | 78 | ||||
-rw-r--r-- | chrome/browser/extensions/external_install_ui.cc | 590 | ||||
-rw-r--r-- | chrome/browser/extensions/external_install_ui.h | 30 | ||||
-rw-r--r-- | chrome/chrome_browser_extensions.gypi | 6 |
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', |