Commit bc44b5da authored by tmdiep@chromium.org's avatar tmdiep@chromium.org

Invoke callback from WebstoreInstaller when installation is fully complete

ExtensionRegistry observers will be notified when an extension install
is fully complete, i.e. after the extension has been loaded or added
to one of the registry extension sets.

This allows the WebstoreInstaller completion to be delayed until the
extension has been loaded. Workarounds in EphemeralAppLauncher for
launching an app can now be cleaned up since we are now assured that
the app has been loaded.

BUG=None
TEST=browser_tests

Review URL: https://codereview.chromium.org/326213004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276666 0039d316-1c4b-4281-b951-d872f2087c98
parent 8aa39ecb
...@@ -5,19 +5,17 @@ ...@@ -5,19 +5,17 @@
#include "chrome/browser/apps/ephemeral_app_launcher.h" #include "chrome/browser/apps/ephemeral_app_launcher.h"
#include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/permissions/permissions_data.h" #include "extensions/common/permissions/permissions_data.h"
using content::WebContents; using content::WebContents;
using extensions::Extension; using extensions::Extension;
using extensions::ExtensionSystem; using extensions::ExtensionRegistry;
using extensions::WebstoreInstaller; using extensions::WebstoreInstaller;
namespace { namespace {
...@@ -72,11 +70,9 @@ EphemeralAppLauncher::CreateForLink( ...@@ -72,11 +70,9 @@ EphemeralAppLauncher::CreateForLink(
} }
void EphemeralAppLauncher::Start() { void EphemeralAppLauncher::Start() {
ExtensionService* extension_service = const Extension* extension =
extensions::ExtensionSystem::Get(profile())->extension_service(); ExtensionRegistry::Get(profile())
DCHECK(extension_service); ->GetExtensionById(id(), ExtensionRegistry::EVERYTHING);
const Extension* extension = extension_service->GetInstalledExtension(id());
if (extension) { if (extension) {
if (extensions::util::IsAppLaunchableWithoutEnabling(extension->id(), if (extensions::util::IsAppLaunchableWithoutEnabling(extension->id(),
profile())) { profile())) {
...@@ -101,7 +97,6 @@ void EphemeralAppLauncher::Start() { ...@@ -101,7 +97,6 @@ void EphemeralAppLauncher::Start() {
} }
// Fetch the app from the webstore. // Fetch the app from the webstore.
StartObserving();
BeginInstall(); BeginInstall();
} }
...@@ -110,7 +105,6 @@ EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id, ...@@ -110,7 +105,6 @@ EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id,
gfx::NativeWindow parent_window, gfx::NativeWindow parent_window,
const Callback& callback) const Callback& callback)
: WebstoreStandaloneInstaller(webstore_item_id, profile, callback), : WebstoreStandaloneInstaller(webstore_item_id, profile, callback),
extension_registry_observer_(this),
parent_window_(parent_window), parent_window_(parent_window),
dummy_web_contents_( dummy_web_contents_(
WebContents::Create(WebContents::CreateParams(profile))) { WebContents::Create(WebContents::CreateParams(profile))) {
...@@ -123,17 +117,11 @@ EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id, ...@@ -123,17 +117,11 @@ EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id,
ProfileForWebContents(web_contents), ProfileForWebContents(web_contents),
callback), callback),
content::WebContentsObserver(web_contents), content::WebContentsObserver(web_contents),
extension_registry_observer_(this),
parent_window_(NativeWindowForWebContents(web_contents)) { parent_window_(NativeWindowForWebContents(web_contents)) {
} }
EphemeralAppLauncher::~EphemeralAppLauncher() {} EphemeralAppLauncher::~EphemeralAppLauncher() {}
void EphemeralAppLauncher::StartObserving() {
extension_registry_observer_.Add(
extensions::ExtensionRegistry::Get(profile()));
}
void EphemeralAppLauncher::LaunchApp(const Extension* extension) const { void EphemeralAppLauncher::LaunchApp(const Extension* extension) const {
DCHECK(extension); DCHECK(extension);
if (!extension->is_app()) { if (!extension->is_app()) {
...@@ -238,46 +226,25 @@ EphemeralAppLauncher::CreateApproval() const { ...@@ -238,46 +226,25 @@ EphemeralAppLauncher::CreateApproval() const {
} }
void EphemeralAppLauncher::CompleteInstall(const std::string& error) { void EphemeralAppLauncher::CompleteInstall(const std::string& error) {
if (!error.empty()) if (error.empty()) {
WebstoreStandaloneInstaller::CompleteInstall(error); const Extension* extension =
ExtensionRegistry::Get(profile())
// If the installation succeeds, we reach this point as a result of ->GetExtensionById(id(), ExtensionRegistry::ENABLED);
// chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED, but this is if (extension)
// broadcasted before LaunchApp(extension);
// ExtensionService has added the extension to its list of installed }
// extensions and is too early to launch the app. Instead, we will launch at
// EphemeralAppLauncher::OnExtensionLoaded(). WebstoreStandaloneInstaller::CompleteInstall(error);
// TODO(tmdiep): Refactor extensions/WebstoreInstaller or
// WebstoreStandaloneInstaller to support this cleanly.
} }
void EphemeralAppLauncher::WebContentsDestroyed() { void EphemeralAppLauncher::WebContentsDestroyed() {
AbortInstall(); AbortInstall();
} }
void EphemeralAppLauncher::OnExtensionLoaded(
content::BrowserContext* browser_context,
const Extension* extension) {
if (extension->id() == id()) {
LaunchApp(extension);
WebstoreStandaloneInstaller::CompleteInstall(std::string());
}
}
void EphemeralAppLauncher::ExtensionEnableFlowFinished() { void EphemeralAppLauncher::ExtensionEnableFlowFinished() {
ExtensionService* extension_service = CompleteInstall(std::string());
extensions::ExtensionSystem::Get(profile())->extension_service();
DCHECK(extension_service);
const Extension* extension = extension_service->GetExtensionById(id(), false);
if (extension) {
LaunchApp(extension);
WebstoreStandaloneInstaller::CompleteInstall(std::string());
} else {
WebstoreStandaloneInstaller::CompleteInstall(kLaunchAbortedError);
}
} }
void EphemeralAppLauncher::ExtensionEnableFlowAborted(bool user_initiated) { void EphemeralAppLauncher::ExtensionEnableFlowAborted(bool user_initiated) {
WebstoreStandaloneInstaller::CompleteInstall(kLaunchAbortedError); CompleteInstall(kLaunchAbortedError);
} }
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "chrome/browser/extensions/webstore_standalone_installer.h" #include "chrome/browser/extensions/webstore_standalone_installer.h"
#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/extension_registry_observer.h"
class ExtensionEnableFlow; class ExtensionEnableFlow;
class Profile; class Profile;
...@@ -31,7 +30,6 @@ class ExtensionRegistry; ...@@ -31,7 +30,6 @@ class ExtensionRegistry;
// launches the app. // launches the app.
class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller, class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller,
public content::WebContentsObserver, public content::WebContentsObserver,
public extensions::ExtensionRegistryObserver,
public ExtensionEnableFlowDelegate { public ExtensionEnableFlowDelegate {
public: public:
typedef WebstoreStandaloneInstaller::Callback Callback; typedef WebstoreStandaloneInstaller::Callback Callback;
...@@ -64,7 +62,6 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller, ...@@ -64,7 +62,6 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller,
virtual ~EphemeralAppLauncher(); virtual ~EphemeralAppLauncher();
void StartObserving();
void LaunchApp(const extensions::Extension* extension) const; void LaunchApp(const extensions::Extension* extension) const;
// WebstoreStandaloneInstaller implementation. // WebstoreStandaloneInstaller implementation.
...@@ -92,20 +89,10 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller, ...@@ -92,20 +89,10 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller,
// content::WebContentsObserver implementation. // content::WebContentsObserver implementation.
virtual void WebContentsDestroyed() OVERRIDE; virtual void WebContentsDestroyed() OVERRIDE;
// ExtensionRegistryObserver implementation.
virtual void OnExtensionLoaded(
content::BrowserContext* browser_context,
const extensions::Extension* extension) OVERRIDE;
// ExtensionEnableFlowDelegate implementation. // ExtensionEnableFlowDelegate implementation.
virtual void ExtensionEnableFlowFinished() OVERRIDE; virtual void ExtensionEnableFlowFinished() OVERRIDE;
virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE; virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
// Listen to extension unloaded notifications.
ScopedObserver<extensions::ExtensionRegistry,
extensions::ExtensionRegistryObserver>
extension_registry_observer_;
gfx::NativeWindow parent_window_; gfx::NativeWindow parent_window_;
scoped_ptr<content::WebContents> dummy_web_contents_; scoped_ptr<content::WebContents> dummy_web_contents_;
......
...@@ -1978,7 +1978,7 @@ void ExtensionService::FinishInstallation( ...@@ -1978,7 +1978,7 @@ void ExtensionService::FinishInstallation(
content::Source<Profile>(profile_), content::Source<Profile>(profile_),
content::Details<const extensions::InstalledExtensionInfo>(&details)); content::Details<const extensions::InstalledExtensionInfo>(&details));
ExtensionRegistry::Get(profile_)->TriggerOnWillBeInstalled( registry_->TriggerOnWillBeInstalled(
extension, is_update, from_ephemeral, old_name); extension, is_update, from_ephemeral, old_name);
bool unacknowledged_external = IsUnacknowledgedExternalExtension(extension); bool unacknowledged_external = IsUnacknowledgedExternalExtension(extension);
...@@ -1992,6 +1992,9 @@ void ExtensionService::FinishInstallation( ...@@ -1992,6 +1992,9 @@ void ExtensionService::FinishInstallation(
AddExtension(extension); AddExtension(extension);
// Notify observers that need to know when an installation is complete.
registry_->TriggerOnInstalled(extension);
// If this is a new external extension that was disabled, alert the user // If this is a new external extension that was disabled, alert the user
// so he can reenable it. We do this last so that it has already been // so he can reenable it. We do this last so that it has already been
// added to our list of extensions. // added to our list of extensions.
...@@ -2078,6 +2081,8 @@ void ExtensionService::PromoteEphemeralApp( ...@@ -2078,6 +2081,8 @@ void ExtensionService::PromoteEphemeralApp(
registry_->TriggerOnLoaded(extension); registry_->TriggerOnLoaded(extension);
} }
registry_->TriggerOnInstalled(extension);
if (!is_from_sync && extension_sync_service_) if (!is_from_sync && extension_sync_service_)
extension_sync_service_->SyncExtensionChangeIfNeeded(*extension); extension_sync_service_->SyncExtensionChangeIfNeeded(*extension);
} }
......
...@@ -399,12 +399,9 @@ void WebstoreInstaller::Observe(int type, ...@@ -399,12 +399,9 @@ void WebstoreInstaller::Observe(int type,
} }
} }
void WebstoreInstaller::OnExtensionWillBeInstalled( void WebstoreInstaller::OnExtensionInstalled(
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
const Extension* extension, const Extension* extension) {
bool is_update,
bool from_ephemeral,
const std::string& old_name) {
CHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context))); CHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
if (pending_modules_.empty()) if (pending_modules_.empty())
return; return;
......
...@@ -160,7 +160,7 @@ class WebstoreInstaller : public content::NotificationObserver, ...@@ -160,7 +160,7 @@ class WebstoreInstaller : public content::NotificationObserver,
// Required minimum version. // Required minimum version.
scoped_ptr<Version> minimum_version; scoped_ptr<Version> minimum_version;
// Ephemeral apps (experimental) are not permanently installed in Chrome. // Ephemeral apps are transiently installed.
bool is_ephemeral; bool is_ephemeral;
// The authuser index required to download the item being installed. May be // The authuser index required to download the item being installed. May be
...@@ -199,12 +199,8 @@ class WebstoreInstaller : public content::NotificationObserver, ...@@ -199,12 +199,8 @@ class WebstoreInstaller : public content::NotificationObserver,
const content::NotificationDetails& details) OVERRIDE; const content::NotificationDetails& details) OVERRIDE;
// ExtensionRegistryObserver. // ExtensionRegistryObserver.
virtual void OnExtensionWillBeInstalled( virtual void OnExtensionInstalled(content::BrowserContext* browser_context,
content::BrowserContext* browser_context, const Extension* extension) OVERRIDE;
const Extension* extension,
bool is_update,
bool from_ephemeral,
const std::string& old_name) OVERRIDE;
// Removes the reference to the delegate passed in the constructor. Used when // Removes the reference to the delegate passed in the constructor. Used when
// the delegate object must be deleted before this object. // the delegate object must be deleted before this object.
......
...@@ -67,6 +67,13 @@ void ExtensionRegistry::TriggerOnWillBeInstalled(const Extension* extension, ...@@ -67,6 +67,13 @@ void ExtensionRegistry::TriggerOnWillBeInstalled(const Extension* extension,
browser_context_, extension, is_update, from_ephemeral, old_name)); browser_context_, extension, is_update, from_ephemeral, old_name));
} }
void ExtensionRegistry::TriggerOnInstalled(const Extension* extension) {
DCHECK(GenerateInstalledExtensionsSet()->Contains(extension->id()));
FOR_EACH_OBSERVER(ExtensionRegistryObserver,
observers_,
OnExtensionInstalled(browser_context_, extension));
}
void ExtensionRegistry::TriggerOnUninstalled(const Extension* extension) { void ExtensionRegistry::TriggerOnUninstalled(const Extension* extension) {
DCHECK(!GenerateInstalledExtensionsSet()->Contains(extension->id())); DCHECK(!GenerateInstalledExtensionsSet()->Contains(extension->id()));
FOR_EACH_OBSERVER(ExtensionRegistryObserver, FOR_EACH_OBSERVER(ExtensionRegistryObserver,
......
...@@ -86,6 +86,10 @@ class ExtensionRegistry : public KeyedService { ...@@ -86,6 +86,10 @@ class ExtensionRegistry : public KeyedService {
bool from_ephemeral, bool from_ephemeral,
const std::string& old_name); const std::string& old_name);
// Invokes the observer method OnExtensionInstalled(). The extension must be
// contained in one of the registry's extension sets.
void TriggerOnInstalled(const Extension* extension);
// Invokes the observer method OnExtensionUninstalled(). The extension must // Invokes the observer method OnExtensionUninstalled(). The extension must
// not be any installed extension with |extension|'s ID. // not be any installed extension with |extension|'s ID.
void TriggerOnUninstalled(const Extension* extension); void TriggerOnUninstalled(const Extension* extension);
......
...@@ -59,7 +59,13 @@ class ExtensionRegistryObserver { ...@@ -59,7 +59,13 @@ class ExtensionRegistryObserver {
bool from_ephemeral, bool from_ephemeral,
const std::string& old_name) {} const std::string& old_name) {}
// Called after an extension is uninstalled. The extension no longer exsit in // Called when the installation of |extension| is complete. At this point the
// extension is tracked in one of the ExtensionRegistry sets, but is not
// necessarily enabled.
virtual void OnExtensionInstalled(content::BrowserContext* browser_context,
const Extension* extension) {}
// Called after an extension is uninstalled. The extension no longer exists in
// any of the ExtensionRegistry sets (enabled, disabled, etc.). // any of the ExtensionRegistry sets (enabled, disabled, etc.).
virtual void OnExtensionUninstalled(content::BrowserContext* browser_context, virtual void OnExtensionUninstalled(content::BrowserContext* browser_context,
const Extension* extension) {} const Extension* extension) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment