| Index: chrome/browser/extensions/external_install_ui.cc
|
| diff --git a/chrome/browser/extensions/external_install_ui.cc b/chrome/browser/extensions/external_install_ui.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0f786468a00ff39f21e2df01a73b1824128013be
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/external_install_ui.cc
|
| @@ -0,0 +1,590 @@
|
| +// 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
|
|
|