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,
}
void ExtensionInstallPrompt::ConfirmExternalInstall(
Delegate* delegate, const Extension* extension) {
Delegate* delegate,
const Extension* extension,
const ShowDialogCallback& show_dialog_callback) {
DCHECK(ui_loop_ == MessageLoop::current());
extension_ = extension;
permissions_ = extension->GetActivePermissions();
delegate_ = delegate;
prompt_.set_type(EXTERNAL_INSTALL_PROMPT);
show_dialog_callback_ = show_dialog_callback;
LoadImageIfNeeded();
}
......
......@@ -268,8 +268,10 @@ class ExtensionInstallPrompt
// extension should be enabled (external extensions are installed disabled).
//
// We *MUST* eventually call either Proceed() or Abort() on |delegate|.
virtual void ConfirmExternalInstall(Delegate* delegate,
const extensions::Extension* extension);
virtual void ConfirmExternalInstall(
Delegate* delegate,
const extensions::Extension* extension,
const ShowDialogCallback& show_dialog_callback);
// This is called by the extension permissions API to verify whether an
// extension may be granted additional permissions.
......
......@@ -36,9 +36,20 @@
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;
// ExternalInstallDialogDelegate --------------------------------------------
class ExternalInstallGlobalError;
// TODO(mpcomplete): Get rid of the refcounting on this class, or document
// why it's necessary. Will do after refactoring to merge back with
......@@ -49,10 +60,12 @@ class ExternalInstallDialogDelegate
public:
ExternalInstallDialogDelegate(Browser* browser,
ExtensionService* service,
const Extension* extension);
const Extension* extension,
ExternalInstallGlobalError* global_error);
private:
friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>;
friend class ExternalInstallGlobalError;
virtual ~ExternalInstallDialogDelegate();
......@@ -67,46 +80,14 @@ class ExternalInstallDialogDelegate
const Extension* extension_;
};
ExternalInstallDialogDelegate::ExternalInstallDialogDelegate(
Browser* browser,
ExtensionService* service,
const Extension* extension)
: 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 {
// Only shows a menu item, no bubble. Clicking the menu item shows
// an external install dialog.
class ExternalInstallMenuAlert : public GlobalError,
public content::NotificationObserver {
public:
ExternalInstallGlobalError(ExtensionService* service,
const Extension* extension);
virtual ~ExternalInstallGlobalError();
ExternalInstallMenuAlert(ExtensionService* service,
const Extension* extension);
virtual ~ExternalInstallMenuAlert();
const Extension* extension() const { return extension_; }
......@@ -131,13 +112,91 @@ class ExternalInstallGlobalError : public GlobalError,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
private:
protected:
ExtensionService* service_;
const Extension* extension_;
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,
const Extension* extension)
: service_(service),
......@@ -148,26 +207,26 @@ ExternalInstallGlobalError::ExternalInstallGlobalError(
content::Source<Profile>(service->profile()));
}
ExternalInstallGlobalError::~ExternalInstallGlobalError() {
ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
}
GlobalError::Severity ExternalInstallGlobalError::GetSeverity() {
GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
return SEVERITY_LOW;
}
bool ExternalInstallGlobalError::HasMenuItem() {
bool ExternalInstallMenuAlert::HasMenuItem() {
return true;
}
int ExternalInstallGlobalError::MenuItemCommandID() {
int ExternalInstallMenuAlert::MenuItemCommandID() {
return kMenuCommandId;
}
int ExternalInstallGlobalError::MenuItemIconResourceID() {
int ExternalInstallMenuAlert::MenuItemIconResourceID() {
return IDR_UPDATE_MENU_EXTENSION;
}
string16 ExternalInstallGlobalError::MenuItemLabel() {
string16 ExternalInstallMenuAlert::MenuItemLabel() {
int id = -1;
if (extension_->is_app())
id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
......@@ -178,45 +237,44 @@ string16 ExternalInstallGlobalError::MenuItemLabel() {
return l10n_util::GetStringFUTF16(id, UTF8ToUTF16(extension_->name()));
}
void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) {
void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
ShowExternalInstallDialog(service_, browser, extension_);
}
bool ExternalInstallGlobalError::HasBubbleView() {
bool ExternalInstallMenuAlert::HasBubbleView() {
return false;
}
string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
string16 ExternalInstallMenuAlert::GetBubbleViewTitle() {
return string16();
}
std::vector<string16> ExternalInstallGlobalError::GetBubbleViewMessages() {
std::vector<string16> ExternalInstallMenuAlert::GetBubbleViewMessages() {
return std::vector<string16>();
}
string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() {
string16 ExternalInstallMenuAlert::GetBubbleViewAcceptButtonLabel() {
return string16();
}
string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() {
string16 ExternalInstallMenuAlert::GetBubbleViewCancelButtonLabel() {
return string16();
}
void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) {
void ExternalInstallMenuAlert::OnBubbleViewDidClose(Browser* browser) {
NOTREACHED();
}
void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed(
void ExternalInstallMenuAlert::BubbleViewAcceptButtonPressed(
Browser* browser) {
NOTREACHED();
}
void ExternalInstallGlobalError::BubbleViewCancelButtonPressed(
void ExternalInstallMenuAlert::BubbleViewCancelButtonPressed(
Browser* browser) {
NOTREACHED();
}
void ExternalInstallGlobalError::Observe(
void ExternalInstallMenuAlert::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
......@@ -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 ---------------------------------------------------------
bool AddExternalInstallError(ExtensionService* service,
......@@ -250,8 +369,13 @@ bool AddExternalInstallError(ExtensionService* service,
if (error)
return false;
error_service->AddGlobalError(
new ExternalInstallGlobalError(service, extension));
if (UseBubbleInstall(extension)) {
error_service->AddGlobalError(
new ExternalInstallGlobalError(service, extension));
} else {
error_service->AddGlobalError(
new ExternalInstallMenuAlert(service, extension));
}
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