Index: chrome/browser/extensions/tab_helper.cc |
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc |
index bc92af0b88af50c8d971f4b81f97573ccb8a3a08..7f66c06504e2027f34fad2f8619a977d2314593c 100644 |
--- a/chrome/browser/extensions/tab_helper.cc |
+++ b/chrome/browser/extensions/tab_helper.cc |
@@ -12,12 +12,14 @@ |
#include "chrome/browser/extensions/activity_log/activity_log.h" |
#include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h" |
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
-#include "chrome/browser/extensions/api/webstore/webstore_api.h" |
#include "chrome/browser/extensions/bookmark_app_helper.h" |
#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" |
#include "chrome/browser/extensions/extension_action_runner.h" |
#include "chrome/browser/extensions/extension_tab_util.h" |
#include "chrome/browser/extensions/extension_util.h" |
+#include "chrome/browser/extensions/install_observer.h" |
+#include "chrome/browser/extensions/install_tracker.h" |
+#include "chrome/browser/extensions/install_tracker_factory.h" |
#include "chrome/browser/extensions/location_bar_controller.h" |
#include "chrome/browser/extensions/webstore_inline_installer.h" |
#include "chrome/browser/extensions/webstore_inline_installer_factory.h" |
@@ -28,6 +30,7 @@ |
#include "chrome/browser/ui/browser_dialogs.h" |
#include "chrome/browser/ui/browser_finder.h" |
#include "chrome/browser/web_applications/web_app.h" |
+#include "chrome/common/extensions/api/webstore/webstore_api_constants.h" |
#include "chrome/common/extensions/chrome_extension_messages.h" |
#include "chrome/common/extensions/extension_constants.h" |
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" |
@@ -72,6 +75,76 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper); |
namespace extensions { |
+// A helper class to watch the progress of inline installation and update the |
+// renderer. Owned by the TabHelper. |
+class TabHelper::InlineInstallObserver : public InstallObserver { |
+ public: |
+ InlineInstallObserver(TabHelper* tab_helper, |
+ content::BrowserContext* browser_context, |
+ int routing_id, |
+ const std::string& extension_id, |
+ bool observe_download_progress, |
+ bool observe_install_stage) |
+ : tab_helper_(tab_helper), |
+ routing_id_(routing_id), |
+ extension_id_(extension_id), |
+ observe_download_progress_(observe_download_progress), |
+ observe_install_stage_(observe_install_stage), |
+ install_observer_(this) { |
+ DCHECK(tab_helper); |
+ DCHECK(observe_download_progress || observe_install_stage); |
+ InstallTracker* install_tracker = |
+ InstallTrackerFactory::GetForBrowserContext(browser_context); |
+ if (install_tracker) |
+ install_observer_.Add(install_tracker); |
+ } |
+ ~InlineInstallObserver() override {} |
+ |
+ private: |
+ // InstallObserver: |
+ void OnBeginExtensionDownload(const std::string& extension_id) override { |
+ SendInstallStageChangedMessage(extension_id, |
+ api::webstore::INSTALL_STAGE_DOWNLOADING); |
+ } |
+ void OnDownloadProgress(const std::string& extension_id, |
+ int percent_downloaded) override { |
+ if (observe_download_progress_ && extension_id == extension_id_) { |
+ tab_helper_->Send(new ExtensionMsg_InlineInstallDownloadProgress( |
+ routing_id_, percent_downloaded)); |
+ } |
+ } |
+ void OnBeginCrxInstall(const std::string& extension_id) override { |
+ SendInstallStageChangedMessage(extension_id, |
+ api::webstore::INSTALL_STAGE_INSTALLING); |
+ } |
+ void OnShutdown() override { install_observer_.RemoveAll(); } |
+ |
+ void SendInstallStageChangedMessage(const std::string& extension_id, |
+ api::webstore::InstallStage stage) { |
+ if (observe_install_stage_ && extension_id == extension_id_) { |
+ tab_helper_->Send( |
+ new ExtensionMsg_InlineInstallStageChanged(routing_id_, stage)); |
+ } |
+ } |
+ |
+ // The owning TabHelper (guaranteed to be valid). |
+ TabHelper* const tab_helper_; |
+ |
+ // The routing id to use in sending IPC updates. |
+ int routing_id_; |
+ |
+ // The id of the extension to observe. |
+ std::string extension_id_; |
+ |
+ // Whether or not to observe download/install progress. |
+ const bool observe_download_progress_; |
+ const bool observe_install_stage_; |
+ |
+ ScopedObserver<InstallTracker, InstallObserver> install_observer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(InlineInstallObserver); |
+}; |
+ |
TabHelper::TabHelper(content::WebContents* web_contents) |
: content::WebContentsObserver(web_contents), |
profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), |
@@ -369,6 +442,16 @@ void TabHelper::OnInlineWebstoreInstall(content::RenderFrameHost* host, |
NOTREACHED(); |
return; |
} |
+ |
+ if (pending_inline_installations_.count(webstore_item_id) != 0) { |
+ Send(new ExtensionMsg_InlineWebstoreInstallResponse( |
+ return_route_id, install_id, false, |
+ webstore_install::kInstallInProgressError, |
+ webstore_install::INSTALL_IN_PROGRESS)); |
+ return; |
+ } |
+ |
+ pending_inline_installations_.insert(webstore_item_id); |
// Inform the Webstore API that an inline install is happening, in case the |
// page requested status updates. |
ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
@@ -382,25 +465,30 @@ void TabHelper::OnInlineWebstoreInstall(content::RenderFrameHost* host, |
// For clarity, explicitly end any prior reenable process. |
extension_reenabler_.reset(); |
extension_reenabler_ = ExtensionReenabler::PromptForReenable( |
- registry->disabled_extensions().GetByID(webstore_item_id), |
- profile_, |
- web_contents(), |
- requestor_url, |
+ registry->disabled_extensions().GetByID(webstore_item_id), profile_, |
+ web_contents(), requestor_url, |
base::Bind(&TabHelper::OnReenableComplete, |
- weak_ptr_factory_.GetWeakPtr(), |
- install_id, |
- return_route_id)); |
+ weak_ptr_factory_.GetWeakPtr(), install_id, |
+ return_route_id, webstore_item_id)); |
} else { |
// TODO(devlin): We should adddress the case of the extension already |
// being installed and enabled. |
- WebstoreAPI::Get(profile_)->OnInlineInstallStart( |
- return_route_id, this, webstore_item_id, listeners_mask); |
- |
- WebstoreStandaloneInstaller::Callback callback = |
- base::Bind(&TabHelper::OnInlineInstallComplete, |
- base::Unretained(this), |
- install_id, |
- return_route_id); |
+ bool observe_download_progress = |
+ (listeners_mask & api::webstore::DOWNLOAD_PROGRESS_LISTENER) != 0; |
+ bool observe_install_stage = |
+ (listeners_mask & api::webstore::INSTALL_STAGE_LISTENER) != 0; |
+ if (observe_install_stage || observe_download_progress) { |
+ DCHECK_EQ(0u, install_observers_.count(webstore_item_id)); |
+ install_observers_[webstore_item_id] = |
+ base::MakeUnique<InlineInstallObserver>( |
+ this, web_contents()->GetBrowserContext(), return_route_id, |
+ webstore_item_id, observe_download_progress, |
+ observe_install_stage); |
+ } |
+ |
+ WebstoreStandaloneInstaller::Callback callback = base::Bind( |
+ &TabHelper::OnInlineInstallComplete, weak_ptr_factory_.GetWeakPtr(), |
+ install_id, return_route_id, webstore_item_id); |
scoped_refptr<WebstoreInlineInstaller> installer( |
webstore_inline_installer_factory_->CreateInstaller( |
web_contents(), host, webstore_item_id, requestor_url, callback)); |
@@ -494,8 +582,8 @@ WindowController* TabHelper::GetExtensionWindowController() const { |
void TabHelper::OnReenableComplete(int install_id, |
int return_route_id, |
+ const std::string& extension_id, |
ExtensionReenabler::ReenableResult result) { |
- extension_reenabler_.reset(); |
// Map the re-enable results to webstore-install results. |
webstore_install::Result webstore_result = webstore_install::SUCCESS; |
std::string error; |
@@ -516,18 +604,23 @@ void TabHelper::OnReenableComplete(int install_id, |
break; |
} |
- OnInlineInstallComplete(install_id, |
- return_route_id, |
- result == ExtensionReenabler::REENABLE_SUCCESS, |
- error, |
+ OnInlineInstallComplete(install_id, return_route_id, extension_id, |
+ result == ExtensionReenabler::REENABLE_SUCCESS, error, |
webstore_result); |
+ // Note: ExtensionReenabler contained the callback with the curried-in |
+ // |extension_id|; delete it last. |
+ extension_reenabler_.reset(); |
} |
void TabHelper::OnInlineInstallComplete(int install_id, |
int return_route_id, |
+ const std::string& extension_id, |
bool success, |
const std::string& error, |
webstore_install::Result result) { |
+ DCHECK_EQ(1u, pending_inline_installations_.count(extension_id)); |
+ pending_inline_installations_.erase(extension_id); |
+ install_observers_.erase(extension_id); |
Send(new ExtensionMsg_InlineWebstoreInstallResponse( |
return_route_id, |
install_id, |