Commit c8ff7c9e authored by yoz@chromium.org's avatar yoz@chromium.org

Streamlined sideload UI for extensions from the webstore.

http://i.imgur.com/OOjPmDJ.png

Sideloaded extensions that have a webstore update URL have a global error bubble replacing the normal extension install dialog.

Still TODO:
- Making this not appear for new profiles.
- Unit tests.

BUG=229083

Review URL: https://chromiumcodereview.appspot.com/14328029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195391 0039d316-1c4b-4281-b951-d872f2087c98
parent 8190aed1
...@@ -520,12 +520,15 @@ void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate, ...@@ -520,12 +520,15 @@ void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
} }
void ExtensionInstallPrompt::ConfirmExternalInstall( void ExtensionInstallPrompt::ConfirmExternalInstall(
Delegate* delegate, const Extension* extension) { Delegate* delegate,
const Extension* extension,
const ShowDialogCallback& show_dialog_callback) {
DCHECK(ui_loop_ == MessageLoop::current()); DCHECK(ui_loop_ == MessageLoop::current());
extension_ = extension; extension_ = extension;
permissions_ = extension->GetActivePermissions(); permissions_ = extension->GetActivePermissions();
delegate_ = delegate; delegate_ = delegate;
prompt_.set_type(EXTERNAL_INSTALL_PROMPT); prompt_.set_type(EXTERNAL_INSTALL_PROMPT);
show_dialog_callback_ = show_dialog_callback;
LoadImageIfNeeded(); LoadImageIfNeeded();
} }
......
...@@ -268,8 +268,10 @@ class ExtensionInstallPrompt ...@@ -268,8 +268,10 @@ class ExtensionInstallPrompt
// extension should be enabled (external extensions are installed disabled). // extension should be enabled (external extensions are installed disabled).
// //
// We *MUST* eventually call either Proceed() or Abort() on |delegate|. // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
virtual void ConfirmExternalInstall(Delegate* delegate, virtual void ConfirmExternalInstall(
const extensions::Extension* extension); Delegate* delegate,
const extensions::Extension* extension,
const ShowDialogCallback& show_dialog_callback);
// This is called by the extension permissions API to verify whether an // This is called by the extension permissions API to verify whether an
// extension may be granted additional permissions. // extension may be granted additional permissions.
......
...@@ -36,9 +36,20 @@ ...@@ -36,9 +36,20 @@
namespace extensions { namespace extensions {
namespace {
// Whether the external extension can use the streamlined bubble install flow.
bool UseBubbleInstall(const Extension* extension) {
// TODO(yoz): determine how to determine if it's a new profile,
// returning false in that case.
return extension->UpdatesFromGallery();
}
} // namespace
static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT; static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT;
// ExternalInstallDialogDelegate -------------------------------------------- class ExternalInstallGlobalError;
// TODO(mpcomplete): Get rid of the refcounting on this class, or document // TODO(mpcomplete): Get rid of the refcounting on this class, or document
// why it's necessary. Will do after refactoring to merge back with // why it's necessary. Will do after refactoring to merge back with
...@@ -49,10 +60,12 @@ class ExternalInstallDialogDelegate ...@@ -49,10 +60,12 @@ class ExternalInstallDialogDelegate
public: public:
ExternalInstallDialogDelegate(Browser* browser, ExternalInstallDialogDelegate(Browser* browser,
ExtensionService* service, ExtensionService* service,
const Extension* extension); const Extension* extension,
ExternalInstallGlobalError* global_error);
private: private:
friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>; friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>;
friend class ExternalInstallGlobalError;
virtual ~ExternalInstallDialogDelegate(); virtual ~ExternalInstallDialogDelegate();
...@@ -67,46 +80,14 @@ class ExternalInstallDialogDelegate ...@@ -67,46 +80,14 @@ class ExternalInstallDialogDelegate
const Extension* extension_; const Extension* extension_;
}; };
ExternalInstallDialogDelegate::ExternalInstallDialogDelegate( // Only shows a menu item, no bubble. Clicking the menu item shows
Browser* browser, // an external install dialog.
ExtensionService* service, class ExternalInstallMenuAlert : public GlobalError,
const Extension* extension) public content::NotificationObserver {
: service_(service), extension_(extension) {
AddRef(); // Balanced in Proceed or Abort.
install_ui_.reset(
ExtensionInstallUI::CreateInstallPromptWithBrowser(browser));
install_ui_->ConfirmExternalInstall(this, extension_);
}
ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() {
}
void ExternalInstallDialogDelegate::InstallUIProceed() {
service_->GrantPermissionsAndEnableExtension(extension_);
Release();
}
void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) {
service_->UninstallExtension(extension_->id(), false, NULL);
Release();
}
static void ShowExternalInstallDialog(ExtensionService* service,
Browser* browser,
const Extension* extension) {
// This object manages its own lifetime.
new ExternalInstallDialogDelegate(browser, service, extension);
}
// ExternalInstallGlobalError -----------------------------------------------
class ExternalInstallGlobalError : public GlobalError,
public content::NotificationObserver {
public: public:
ExternalInstallGlobalError(ExtensionService* service, ExternalInstallMenuAlert(ExtensionService* service,
const Extension* extension); const Extension* extension);
virtual ~ExternalInstallGlobalError(); virtual ~ExternalInstallMenuAlert();
const Extension* extension() const { return extension_; } const Extension* extension() const { return extension_; }
...@@ -131,13 +112,91 @@ class ExternalInstallGlobalError : public GlobalError, ...@@ -131,13 +112,91 @@ class ExternalInstallGlobalError : public GlobalError,
const content::NotificationSource& source, const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE; const content::NotificationDetails& details) OVERRIDE;
private: protected:
ExtensionService* service_; ExtensionService* service_;
const Extension* extension_; const Extension* extension_;
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
}; };
ExternalInstallGlobalError::ExternalInstallGlobalError( // Shows a menu item and a global error bubble, replacing the install dialog.
class ExternalInstallGlobalError : public ExternalInstallMenuAlert {
public:
ExternalInstallGlobalError(ExtensionService* service,
const Extension* extension);
virtual ~ExternalInstallGlobalError();
void set_prompt(const ExtensionInstallPrompt::Prompt& prompt) {
prompt_ = &prompt;
}
virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
virtual bool HasBubbleView() OVERRIDE;
virtual string16 GetBubbleViewTitle() OVERRIDE;
virtual std::vector<string16> GetBubbleViewMessages() OVERRIDE;
virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
protected:
// Manages its own lifetime.
ExternalInstallDialogDelegate* delegate_;
const ExtensionInstallPrompt::Prompt* prompt_;
};
static void SetExternalInstallBubble(
ExternalInstallGlobalError* global_error,
const ExtensionInstallPrompt::ShowParams& show_params,
ExtensionInstallPrompt::Delegate* delegate,
const ExtensionInstallPrompt::Prompt& prompt) {
global_error->set_prompt(prompt);
}
static void ShowExternalInstallDialog(
ExtensionService* service,
Browser* browser,
const Extension* extension) {
// This object manages its own lifetime.
new ExternalInstallDialogDelegate(browser, service, extension, NULL);
}
// ExternalInstallDialogDelegate --------------------------------------------
ExternalInstallDialogDelegate::ExternalInstallDialogDelegate(
Browser* browser,
ExtensionService* service,
const Extension* extension,
ExternalInstallGlobalError* global_error)
: service_(service), extension_(extension) {
AddRef(); // Balanced in Proceed or Abort.
install_ui_.reset(
ExtensionInstallUI::CreateInstallPromptWithBrowser(browser));
const ExtensionInstallPrompt::ShowDialogCallback callback =
global_error ?
base::Bind(&SetExternalInstallBubble, global_error) :
ExtensionInstallPrompt::GetDefaultShowDialogCallback();
install_ui_->ConfirmExternalInstall(this, extension_, callback);
}
ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() {
}
void ExternalInstallDialogDelegate::InstallUIProceed() {
service_->GrantPermissionsAndEnableExtension(extension_);
Release();
}
void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) {
service_->UninstallExtension(extension_->id(), false, NULL);
Release();
}
// ExternalInstallMenuAlert -------------------------------------------------
ExternalInstallMenuAlert::ExternalInstallMenuAlert(
ExtensionService* service, ExtensionService* service,
const Extension* extension) const Extension* extension)
: service_(service), : service_(service),
...@@ -148,26 +207,26 @@ ExternalInstallGlobalError::ExternalInstallGlobalError( ...@@ -148,26 +207,26 @@ ExternalInstallGlobalError::ExternalInstallGlobalError(
content::Source<Profile>(service->profile())); content::Source<Profile>(service->profile()));
} }
ExternalInstallGlobalError::~ExternalInstallGlobalError() { ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
} }
GlobalError::Severity ExternalInstallGlobalError::GetSeverity() { GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
return SEVERITY_LOW; return SEVERITY_LOW;
} }
bool ExternalInstallGlobalError::HasMenuItem() { bool ExternalInstallMenuAlert::HasMenuItem() {
return true; return true;
} }
int ExternalInstallGlobalError::MenuItemCommandID() { int ExternalInstallMenuAlert::MenuItemCommandID() {
return kMenuCommandId; return kMenuCommandId;
} }
int ExternalInstallGlobalError::MenuItemIconResourceID() { int ExternalInstallMenuAlert::MenuItemIconResourceID() {
return IDR_UPDATE_MENU_EXTENSION; return IDR_UPDATE_MENU_EXTENSION;
} }
string16 ExternalInstallGlobalError::MenuItemLabel() { string16 ExternalInstallMenuAlert::MenuItemLabel() {
int id = -1; int id = -1;
if (extension_->is_app()) if (extension_->is_app())
id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP; id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
...@@ -178,45 +237,44 @@ string16 ExternalInstallGlobalError::MenuItemLabel() { ...@@ -178,45 +237,44 @@ string16 ExternalInstallGlobalError::MenuItemLabel() {
return l10n_util::GetStringFUTF16(id, UTF8ToUTF16(extension_->name())); return l10n_util::GetStringFUTF16(id, UTF8ToUTF16(extension_->name()));
} }
void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) { void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
ShowExternalInstallDialog(service_, browser, extension_); ShowExternalInstallDialog(service_, browser, extension_);
} }
bool ExternalInstallGlobalError::HasBubbleView() { bool ExternalInstallMenuAlert::HasBubbleView() {
return false; return false;
} }
string16 ExternalInstallMenuAlert::GetBubbleViewTitle() {
string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
return string16(); return string16();
} }
std::vector<string16> ExternalInstallGlobalError::GetBubbleViewMessages() { std::vector<string16> ExternalInstallMenuAlert::GetBubbleViewMessages() {
return std::vector<string16>(); return std::vector<string16>();
} }
string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() { string16 ExternalInstallMenuAlert::GetBubbleViewAcceptButtonLabel() {
return string16(); return string16();
} }
string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() { string16 ExternalInstallMenuAlert::GetBubbleViewCancelButtonLabel() {
return string16(); return string16();
} }
void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) { void ExternalInstallMenuAlert::OnBubbleViewDidClose(Browser* browser) {
NOTREACHED(); NOTREACHED();
} }
void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed( void ExternalInstallMenuAlert::BubbleViewAcceptButtonPressed(
Browser* browser) { Browser* browser) {
NOTREACHED(); NOTREACHED();
} }
void ExternalInstallGlobalError::BubbleViewCancelButtonPressed( void ExternalInstallMenuAlert::BubbleViewCancelButtonPressed(
Browser* browser) { Browser* browser) {
NOTREACHED(); NOTREACHED();
} }
void ExternalInstallGlobalError::Observe( void ExternalInstallMenuAlert::Observe(
int type, int type,
const content::NotificationSource& source, const content::NotificationSource& source,
const content::NotificationDetails& details) { const content::NotificationDetails& details) {
...@@ -239,6 +297,67 @@ void ExternalInstallGlobalError::Observe( ...@@ -239,6 +297,67 @@ void ExternalInstallGlobalError::Observe(
} }
} }
// ExternalInstallGlobalError -----------------------------------------------
ExternalInstallGlobalError::ExternalInstallGlobalError(
ExtensionService* service,
const Extension* extension)
: ExternalInstallMenuAlert(service, extension) {
delegate_ = new ExternalInstallDialogDelegate(
NULL, service_, extension_, this);
}
ExternalInstallGlobalError::~ExternalInstallGlobalError() {
}
void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) {
ShowBubbleView(browser);
}
bool ExternalInstallGlobalError::HasBubbleView() {
return true;
}
string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
return prompt_->GetDialogTitle();
}
std::vector<string16> ExternalInstallGlobalError::GetBubbleViewMessages() {
std::vector<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;
}
string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() {
return prompt_->GetAcceptButtonLabel();
}
string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() {
return prompt_->GetAbortButtonLabel();
}
void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) {
}
void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed(
Browser* browser) {
delegate_->InstallUIProceed();
}
void ExternalInstallGlobalError::BubbleViewCancelButtonPressed(
Browser* browser) {
delegate_->InstallUIAbort(true);
}
// Public interface --------------------------------------------------------- // Public interface ---------------------------------------------------------
bool AddExternalInstallError(ExtensionService* service, bool AddExternalInstallError(ExtensionService* service,
...@@ -250,8 +369,13 @@ bool AddExternalInstallError(ExtensionService* service, ...@@ -250,8 +369,13 @@ bool AddExternalInstallError(ExtensionService* service,
if (error) if (error)
return false; return false;
error_service->AddGlobalError( if (UseBubbleInstall(extension)) {
new ExternalInstallGlobalError(service, extension)); error_service->AddGlobalError(
new ExternalInstallGlobalError(service, extension));
} else {
error_service->AddGlobalError(
new ExternalInstallMenuAlert(service, extension));
}
return true; return true;
} }
......
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