summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-04 06:46:21 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-04 06:46:21 +0000
commitd2817019145d7806d400ae70bf9fb4b5681905c8 (patch)
tree21cf799953ab964c5d089bdb519b86bae4823269
parenta3a63ff836382403dc681befbd1cc866e8e5c117 (diff)
downloadchromium_src-d2817019145d7806d400ae70bf9fb4b5681905c8.zip
chromium_src-d2817019145d7806d400ae70bf9fb4b5681905c8.tar.gz
chromium_src-d2817019145d7806d400ae70bf9fb4b5681905c8.tar.bz2
Implement first cut at the extension installation prompt on Windows.
Had to move set_path() earlier in the unpack process so that we would have real paths for the resources, so that we could load and display the icon in the ui. This exposed a problem where page actions had absolute paths and other images in extensions had relative paths. Extension::GetBrowserImages() was expecting relative paths, and it just happened to work because in both cases Extension was initialized without a path. Modified page actions to use relative paths to be consistent with other images. Review URL: http://codereview.chromium.org/160516 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22368 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd32
-rw-r--r--chrome/browser/extensions/crx_installer.cc71
-rw-r--r--chrome/browser/extensions/crx_installer.h31
-rw-r--r--chrome/browser/extensions/extension_file_util.cc9
-rw-r--r--chrome/browser/extensions/extension_install_ui.cc35
-rw-r--r--chrome/browser/extensions/extension_install_ui.h12
-rw-r--r--chrome/browser/extensions/extension_prefs.cc2
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.cc7
-rw-r--r--chrome/browser/extensions/theme_preview_infobar_delegate.cc4
-rw-r--r--chrome/browser/extensions/theme_preview_infobar_delegate.h3
-rw-r--r--chrome/browser/views/extensions/extension_install_prompt.cc194
-rw-r--r--chrome/browser/views/location_bar_view.cc10
-rw-r--r--chrome/chrome.gyp1
-rw-r--r--chrome/common/extensions/extension.cc24
-rw-r--r--chrome/common/extensions/extension.h11
-rw-r--r--chrome/common/extensions/extension_unittest.cc8
-rw-r--r--chrome/common/page_action.h8
17 files changed, 401 insertions, 61 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index d0f5856..dc83d77 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2068,13 +2068,39 @@ each locale. -->
The following extension has crashed : <ph name="EXTENSION_NAME">$1<ex>Buildbot Monitor</ex></ph>
</message>
- <!-- Extension Crashed Info Bar-->
- <message name="IDS_THEME_PREVIEW_INFOBAR_LABEL" desc="Text displayed on an infobar when a theme has been installed.">
+ <!-- Theme preview info bar -->
+ <message name="IDS_THEME_INSTALL_INFOBAR_LABEL" desc="Text displayed on an infobar when a theme has been installed.">
Installed theme "<ph name="THEME_NAME">$1<ex>Snowflake Theme</ex></ph>"
</message>
- <message name="IDS_THEME_PREVIEW_INFOBAR_UNDO_BUTTON" desc="Text displayed on the button to reject a theme preview and go back to the default theme.">
+ <message name="IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON" desc="Text displayed on the button to undo a theme installation and go back to the default theme.">
Back to default
</message>
+
+ <!-- Extesion install prompt -->
+ <message name="IDS_EXTENSION_PROMPT_TITLE" desc="Titlebar of the extension installation prompt window">
+ Confirm Installation
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_HEADING" desc="First bold line in the content area of the extension installation prompt. Asks the user if they want to install a particular extension.">
+ Install "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"?
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_1" desc="Humorous warning displayed in the extension install prompt that tells users that extensions have access to their computer and private data.">
+ Extensions have access your computer and private data. This means they could forward all your email to your spouse.
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_2" desc="Humorous warning displayed in the extension install prompt that tells users that extensions have access to their computer and private data.">
+ Extensions have access your computer and private data. They could send tweets or email on your behalf.
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_3" desc="Humorous warning displayed in the extension install prompt that tells users that extensions have access to their computer and private data.">
+ Extensions can access your computer and private data. They could post unflattering pictures to your Wall.
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_SEVERE" desc="A bolded warning below the humorous warning that reiterates that users should only install extensions they trust">
+ Only install extensions you trust.
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_INSTALL_BUTTON" desc="Text for the install button on the extension install prompt">
+ Install
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_CANCEL_BUTTON" desc="Text for the cancel button on the extension install prompt">
+ Cancel
+ </message>
<!-- Session Crashed Info Bar-->
<message name="IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON" desc="Title of the restore button in the session crashed view.">
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 60fe23e..5fede2e 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -13,6 +13,8 @@
#include "chrome/browser/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_error_reporter.h"
#include "grit/chromium_strings.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "webkit/glue/image_decoder.h"
namespace {
// Helper function to delete files. This is used to avoid ugly casts which
@@ -116,6 +118,7 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
}
if (client_.get()) {
+ DecodeInstallIcon();
ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
&CrxInstaller::ConfirmInstall));
} else {
@@ -123,16 +126,60 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
}
}
-void CrxInstaller::ConfirmInstall() {
- if (!client_->ConfirmInstall(extension_.get())) {
- // We're done. Since we don't post any more tasks to ourselves, our ref
- // count should go to zero and we die. The destructor will clean up the temp
- // dir.
+void CrxInstaller::DecodeInstallIcon() {
+ std::map<int, std::string>::const_iterator iter =
+ extension_->icons().find(128);
+ if (iter == extension_->icons().end())
+ return;
+
+ FilePath path = extension_->GetResourcePath(iter->second);
+ std::string file_contents;
+ if (!file_util::ReadFileToString(path, &file_contents)) {
+ LOG(ERROR) << "Could not read icon file: "
+ << WideToUTF8(path.ToWStringHack());
+ return;
+ }
+
+ // Decode the image using WebKit's image decoder.
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(file_contents.data());
+ webkit_glue::ImageDecoder decoder;
+ scoped_ptr<SkBitmap> decoded(new SkBitmap());
+ *decoded = decoder.Decode(data, file_contents.length());
+ if(decoded->empty()) {
+ LOG(ERROR) << "Could not decode icon file: "
+ << WideToUTF8(path.ToWStringHack());
return;
}
+ if (decoded->width() != 128 || decoded->height() != 128) {
+ LOG(ERROR) << "Icon file has unexpected size: "
+ << IntToString(decoded->width()) << "x"
+ << IntToString(decoded->height());
+ return;
+ }
+
+ install_icon_.reset(decoded.release());
+}
+
+void CrxInstaller::ConfirmInstall() {
+ AddRef(); // balanced in ContinueInstall() and AbortInstall().
+
+ client_->ConfirmInstall(this, extension_.get(), install_icon_.get());
+}
+
+void CrxInstaller::ContinueInstall() {
file_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
&CrxInstaller::CompleteInstall));
+
+ Release(); // balanced in ConfirmInstall().
+}
+
+void CrxInstaller::AbortInstall() {
+ Release(); // balanced in ConfirmInstall().
+
+ // We're done. Since we don't post any more tasks to ourself, our ref count
+ // should go to zero and we die. The destructor will clean up the temp dir.
}
void CrxInstaller::CompleteInstall() {
@@ -156,15 +203,23 @@ void CrxInstaller::CompleteInstall() {
return;
}
- extension_->set_path(version_dir);
- extension_->set_location(install_source_);
-
if (install_type == Extension::REINSTALL) {
// We use this as a signal to switch themes.
ReportOverinstallFromFileThread();
return;
}
+ // This is lame, but we must reload the extension because absolute paths
+ // inside the content scripts are established inside InitFromValue() and we
+ // just moved the extension.
+ // TODO(aa): All paths to resources inside extensions should be created
+ // lazily and based on the Extension's root path at that moment.
+ std::string error;
+ extension_.reset(extension_file_util::LoadExtension(version_dir, true,
+ &error));
+ DCHECK(error.empty());
+ extension_->set_location(install_source_);
+
ReportSuccessFromFileThread();
}
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 5c373d9..0ea8398 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -14,6 +14,9 @@
#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
#include "chrome/common/extensions/extension.h"
+class CrxInstaller;
+class SkBitmap;
+
// Classes that want to know about install completion, or that want to have an
// opportunity to reject the unpacked extension before installation, should
// implement this interface.
@@ -22,8 +25,17 @@ class CrxInstallerClient
public:
virtual ~CrxInstallerClient() {}
- // Return true to indicate that installation should proceed, false otherwise.
- virtual bool ConfirmInstall(Extension* extension) = 0;
+ // This is called by the installer to verify whether the installation should
+ // proceed. Clients can use this time to put up UI, or to do any checks they
+ // need to on the unpacked extension.
+ //
+ // Clients *MUST* eventually call either ContinueInstall() or AbortInstall()
+ // on |installer|.
+ //
+ // Clients should not AddRef() |installer|.
+ virtual void ConfirmInstall(CrxInstaller* installer,
+ Extension* extension,
+ SkBitmap* icon) = 0;
// Installation was successful.
virtual void OnInstallSuccess(Extension* extension) = 0;
@@ -79,6 +91,14 @@ class CrxInstaller : public SandboxedExtensionUnpackerClient {
ExtensionsService* frontend,
CrxInstallerClient* client);
+ // Clients should call this method after ConfirmInstall() if they want the
+ // installation to continue.
+ void ContinueInstall();
+
+ // Clients should call this method after ConfirmInstall() if they want the
+ // installation to stop.
+ void AbortInstall();
+
private:
CrxInstaller(const FilePath& crx_path,
const FilePath& install_directory,
@@ -96,6 +116,10 @@ class CrxInstaller : public SandboxedExtensionUnpackerClient {
const FilePath& extension_dir,
Extension* extension);
+ // Read the icon from the extension if present and decode it into
+ // install_icon_.
+ void DecodeInstallIcon();
+
// Runs on the UI thread. Confirms with the user (via CrxInstallerClient) that
// it is OK to install this extension.
void ConfirmInstall();
@@ -145,6 +169,9 @@ class CrxInstaller : public SandboxedExtensionUnpackerClient {
// ExtensionsService on success, or delete it on failure.
scoped_ptr<Extension> extension_;
+ // The icon we will display in the installation UI, if any.
+ scoped_ptr<SkBitmap> install_icon_;
+
// The temp directory extension resources were unpacked to. We own this and
// must delete it when we are done with it.
FilePath temp_dir_;
diff --git a/chrome/browser/extensions/extension_file_util.cc b/chrome/browser/extensions/extension_file_util.cc
index b46404c..9020b1b 100644
--- a/chrome/browser/extensions/extension_file_util.cc
+++ b/chrome/browser/extensions/extension_file_util.cc
@@ -254,13 +254,12 @@ Extension* LoadExtension(const FilePath& extension_path, bool require_key,
for (PageActionMap::const_iterator i(page_actions.begin());
i != page_actions.end(); ++i) {
PageAction* page_action = i->second;
- const std::vector<FilePath>& icon_paths = page_action->icon_paths();
- for (std::vector<FilePath>::const_iterator iter = icon_paths.begin();
+ const std::vector<std::string>& icon_paths = page_action->icon_paths();
+ for (std::vector<std::string>::const_iterator iter = icon_paths.begin();
iter != icon_paths.end(); ++iter) {
- FilePath path = *iter;
- if (!file_util::PathExists(path)) {
+ if (!file_util::PathExists(extension->GetResourcePath(*iter))) {
*error = StringPrintf("Could not load icon '%s' for page action.",
- WideToUTF8(path.ToWStringHack()).c_str());
+ iter->c_str());
return NULL;
}
}
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index 4416701..135aac7 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -4,12 +4,17 @@
#include "chrome/browser/extensions/extension_install_ui.h"
+#include <map>
+
#include "app/l10n_util.h"
-#include "grit/chromium_strings.h"
+#include "base/file_util.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/theme_preview_infobar_delegate.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/extensions/extension.h"
+#include "grit/chromium_strings.h"
#if defined(OS_WIN)
#include "app/win_util.h"
@@ -23,24 +28,24 @@ ExtensionInstallUI::ExtensionInstallUI(Profile* profile)
: profile_(profile), ui_loop_(MessageLoop::current()) {
}
-bool ExtensionInstallUI::ConfirmInstall(Extension* extension) {
+void ExtensionInstallUI::ConfirmInstall(CrxInstaller* installer,
+ Extension* extension,
+ SkBitmap* install_icon) {
DCHECK(ui_loop_ == MessageLoop::current());
// We special-case themes to not show any confirm UI. Instead they are
// immediately installed, and then we show an infobar (see OnInstallSuccess)
// to allow the user to revert if they don't like it.
- if (extension->IsTheme())
- return true;
+ if (extension->IsTheme()) {
+ installer->ContinueInstall();
+ return;
+ }
#if defined(OS_WIN)
- if (win_util::MessageBox(GetForegroundWindow(),
- L"Are you sure you want to install this extension?\n\n"
- L"You should only install extensions from sources you trust.",
- l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
- MB_OKCANCEL) != IDOK) {
- return false;
- }
+ ShowExtensionInstallPrompt(profile_, installer, extension, install_icon);
+
#elif defined(OS_MACOSX)
+ // TODO(port): Implement nicer UI.
// Using CoreFoundation to do this dialog is unimaginably lame but will do
// until the UI is redone.
scoped_cftyperef<CFStringRef> product_name(
@@ -53,13 +58,15 @@ bool ExtensionInstallUI::ConfirmInstall(Extension* extension) {
"This is a temporary message and it will be removed when "
"extensions UI is finalized."),
NULL, CFSTR("Cancel"), NULL, &response)) {
- return false;
+ installer->AbortInstall();
+ } else {
+ installer->ContinueInstall();
}
#else
+ // TODO(port): Implement some UI.
NOTREACHED();
+ installer->ContinueInstall();
#endif // OS_*
-
- return true;
}
void ExtensionInstallUI::OnInstallSuccess(Extension* extension) {
diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h
index 1fc0379..9cdc5ac 100644
--- a/chrome/browser/extensions/extension_install_ui.h
+++ b/chrome/browser/extensions/extension_install_ui.h
@@ -16,16 +16,20 @@ class Profile;
class SandboxedExtensionUnpacker;
// Displays all the UI around extension installation.
-//
-// TODO(aa): This will become a view and move to browser/views/extensions in the
-// future.
class ExtensionInstallUI : public CrxInstallerClient {
public:
+ // NOTE: The implementation of this is platform-specific.
+ static void ShowExtensionInstallPrompt(Profile* profile,
+ CrxInstaller* installer,
+ Extension* extension,
+ SkBitmap* install_icon);
+
ExtensionInstallUI(Profile* profile);
private:
// CrxInstallerClient
- virtual bool ConfirmInstall(Extension* extension);
+ virtual void ConfirmInstall(CrxInstaller* installer, Extension* extension,
+ SkBitmap* icon);
virtual void OnInstallSuccess(Extension* extension);
virtual void OnInstallFailure(const std::string& error);
virtual void OnOverinstallAttempted(Extension* extension);
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 08a99a4..7b4d061 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -213,7 +213,7 @@ void ExtensionPrefs::OnExtensionInstalled(Extension* extension) {
FilePath::StringType path = MakePathRelative(install_directory_,
extension->path(), NULL);
UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path));
- prefs_->ScheduleSavePersistentPrefs();
+ prefs_->SavePersistentPrefs();
}
void ExtensionPrefs::OnExtensionUninstalled(const Extension* extension,
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
index 46a8382..c736f39 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
@@ -119,6 +119,13 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded(
// originals are gone for good.
extension_.reset(new Extension);
std::string manifest_error;
+
+ // Update the path to refer to the temporary location. We do this because
+ // clients may want to use resources inside the extension before it is
+ // installed and they need the correct path. For example, the install UI shows
+ // one of the icons from the extension.
+ extension_->set_path(extension_root_);
+
if (!extension_->InitFromValue(*final_manifest, true, // require id
&manifest_error)) {
ReportFailure(std::string("Manifest is invalid: ") +
diff --git a/chrome/browser/extensions/theme_preview_infobar_delegate.cc b/chrome/browser/extensions/theme_preview_infobar_delegate.cc
index d22ebda..a1a179f 100644
--- a/chrome/browser/extensions/theme_preview_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_preview_infobar_delegate.cc
@@ -21,7 +21,7 @@ void ThemePreviewInfobarDelegate::InfoBarClosed() {
}
std::wstring ThemePreviewInfobarDelegate::GetMessageText() const {
- return l10n_util::GetStringF(IDS_THEME_PREVIEW_INFOBAR_LABEL,
+ return l10n_util::GetStringF(IDS_THEME_INSTALL_INFOBAR_LABEL,
UTF8ToWide(name_));
}
@@ -44,7 +44,7 @@ std::wstring ThemePreviewInfobarDelegate::GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const {
switch (button) {
case BUTTON_CANCEL:
- return l10n_util::GetString(IDS_THEME_PREVIEW_INFOBAR_UNDO_BUTTON);
+ return l10n_util::GetString(IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON);
default:
return L"";
}
diff --git a/chrome/browser/extensions/theme_preview_infobar_delegate.h b/chrome/browser/extensions/theme_preview_infobar_delegate.h
index 54a8507..dcc34b6 100644
--- a/chrome/browser/extensions/theme_preview_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_preview_infobar_delegate.h
@@ -14,6 +14,9 @@ class TabContents;
// When a user installs a theme, we display it immediately, but provide an
// infobar allowing them to cancel.
+//
+// TODO(aa): Rename this to ThemeInstalledInfoBarDelegate, since it isn't
+// used for previewing anymore.
class ThemePreviewInfobarDelegate : public ConfirmInfoBarDelegate {
public:
ThemePreviewInfobarDelegate(TabContents* tab_contents,
diff --git a/chrome/browser/views/extensions/extension_install_prompt.cc b/chrome/browser/views/extensions/extension_install_prompt.cc
new file mode 100644
index 0000000..e110464
--- /dev/null
+++ b/chrome/browser/views/extensions/extension_install_prompt.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2009 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 "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/rand_util.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/common/extensions/extension.h"
+#include "grit/generated_resources.h"
+#include "views/controls/image_view.h"
+#include "views/controls/label.h"
+#include "views/controls/link.h"
+#include "views/standard_layout.h"
+#include "views/view.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
+
+class Profile;
+
+namespace {
+
+const int kRightColumnWidth = 290;
+
+// Implements the extension installation prompt for Windows.
+// TODO(aa): It would be cool to add an "extensions threat level" when we have
+// granular permissions implemented:
+// - red: npapi
+// - orange: access to any domains
+// - yellow: access to browser data
+// - green: nothing
+// We could have a collection of funny descriptions for each color.
+class InstallDialogContent : public views::View, public views::DialogDelegate {
+ public:
+ InstallDialogContent(CrxInstaller* crx_installer, Extension* extension,
+ SkBitmap* icon)
+ : crx_installer_(crx_installer), icon_(NULL) {
+ if (icon) {
+ icon_ = new views::ImageView();
+ icon_->SetImage(*icon);
+ AddChildView(icon_);
+ }
+
+ heading_ = new views::Label(
+ l10n_util::GetStringF(IDS_EXTENSION_PROMPT_HEADING,
+ UTF8ToWide(extension->name())));
+ heading_->SetFont(heading_->GetFont().DeriveFont(1, gfx::Font::BOLD));
+ heading_->SetMultiLine(true);
+ heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ AddChildView(heading_);
+
+ // Pick a random warning.
+ std::wstring warnings[] = {
+ l10n_util::GetString(IDS_EXTENSION_PROMPT_WARNING_1),
+ l10n_util::GetString(IDS_EXTENSION_PROMPT_WARNING_2),
+ l10n_util::GetString(IDS_EXTENSION_PROMPT_WARNING_3)
+ };
+ warning_ = new views::Label(
+ warnings[base::RandInt(0, arraysize(warnings) - 1)]);
+ warning_->SetMultiLine(true);
+ warning_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ AddChildView(warning_);
+
+ severe_ = new views::Label(
+ l10n_util::GetString(IDS_EXTENSION_PROMPT_WARNING_SEVERE));
+ severe_->SetMultiLine(true);
+ severe_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ severe_->SetFont(heading_->GetFont().DeriveFont(0, gfx::Font::BOLD));
+ severe_->SetColor(SK_ColorRED);
+ AddChildView(severe_);
+ }
+
+ private:
+ // DialogDelegate
+ virtual std::wstring GetDialogButtonLabel(
+ MessageBoxFlags::DialogButton button) const {
+ switch (button) {
+ case MessageBoxFlags::DIALOGBUTTON_OK:
+ return l10n_util::GetString(IDS_EXTENSION_PROMPT_INSTALL_BUTTON);
+ case MessageBoxFlags::DIALOGBUTTON_CANCEL:
+ return l10n_util::GetString(IDS_EXTENSION_PROMPT_CANCEL_BUTTON);
+ default:
+ NOTREACHED();
+ return L"";
+ }
+ }
+
+ virtual int GetDefaultDialogButton() const {
+ return MessageBoxFlags::DIALOGBUTTON_CANCEL;
+ }
+
+ virtual bool Accept() {
+ crx_installer_->ContinueInstall();
+ return true;
+ }
+
+ virtual bool Cancel() {
+ crx_installer_->AbortInstall();
+ return true;
+ }
+
+
+ // WindowDelegate
+ virtual bool IsModal() const { return true; }
+ virtual std::wstring GetWindowTitle() const {
+ return l10n_util::GetString(IDS_EXTENSION_PROMPT_TITLE);
+ }
+ virtual views::View* GetContentsView() { return this; }
+
+ // View
+ virtual gfx::Size GetPreferredSize() {
+ int width = kRightColumnWidth + kPanelHorizMargin + kPanelHorizMargin;
+
+ if (icon_) {
+ width += Extension::EXTENSION_ICON_LARGE;
+ width += kPanelHorizMargin;
+ }
+
+ int height = kPanelVertMargin * 2;
+ height += heading_->GetHeightForWidth(kRightColumnWidth);
+ height += kPanelVertMargin;
+ height += warning_->GetHeightForWidth(kRightColumnWidth);
+ height += kPanelVertMargin;
+ height += severe_->GetHeightForWidth(kRightColumnWidth);
+ height += kPanelVertMargin;
+
+ return gfx::Size(width, std::max(height,
+ static_cast<int>(Extension::EXTENSION_ICON_LARGE)));
+ }
+
+ virtual void Layout() {
+ int x = kPanelHorizMargin;
+ int y = kPanelVertMargin;
+
+ if (icon_) {
+ icon_->SetBounds(x, y, Extension::EXTENSION_ICON_LARGE,
+ Extension::EXTENSION_ICON_LARGE);
+ x += Extension::EXTENSION_ICON_LARGE;
+ x += kPanelHorizMargin;
+ }
+
+ heading_->SizeToFit(kRightColumnWidth);
+ heading_->SetX(x);
+ heading_->SetY(y);
+ y += heading_->height();
+
+ y += kPanelVertMargin;
+
+ warning_->SizeToFit(kRightColumnWidth);
+ warning_->SetX(x);
+ warning_->SetY(y);
+ y += warning_->height();
+
+ y += kPanelVertMargin;
+
+ severe_->SizeToFit(kRightColumnWidth);
+ severe_->SetX(x);
+ severe_->SetY(y);
+ y += severe_->height();
+ }
+
+ scoped_refptr<CrxInstaller> crx_installer_;
+ views::ImageView* icon_;
+ views::Label* heading_;
+ views::Label* warning_;
+ views::Label* severe_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstallDialogContent);
+};
+
+} // namespace
+
+void ExtensionInstallUI::ShowExtensionInstallPrompt(Profile* profile,
+ CrxInstaller* crx_installer,
+ Extension* extension,
+ SkBitmap* icon) {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
+ if (!browser) {
+ crx_installer->AbortInstall();
+ return;
+ }
+
+ BrowserWindow* window = browser->window();
+ if (!window) {
+ crx_installer->AbortInstall();
+ return;
+ }
+
+ views::Window::CreateChromeWindow(window->GetNativeHandle(), gfx::Rect(),
+ new InstallDialogContent(crx_installer, extension, icon))->Show();
+}
diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc
index 674cdb6..bed40dc 100644
--- a/chrome/browser/views/location_bar_view.cc
+++ b/chrome/browser/views/location_bar_view.cc
@@ -1263,18 +1263,22 @@ LocationBarView::PageActionImageView::PageActionImageView(
page_action_(page_action),
current_tab_id_(-1),
tooltip_(page_action_->name()) {
+ Extension* extension = profile->GetExtensionsService()->GetExtensionById(
+ page_action->extension_id());
+ DCHECK(extension);
+
// Load the images this view needs asynchronously on the file thread. We'll
// get a call back into OnImageLoaded if the image loads successfully. If not,
// the ImageView will have no image and will not appear in the Omnibox.
DCHECK(!page_action->icon_paths().empty());
- const std::vector<FilePath>& icon_paths = page_action->icon_paths();
+ const std::vector<std::string>& icon_paths = page_action->icon_paths();
page_action_icons_.resize(icon_paths.size());
int index = 0;
MessageLoop* file_loop = g_browser_process->file_thread()->message_loop();
tracker_ = new ImageLoadingTracker(this, icon_paths.size());
- for (std::vector<FilePath>::const_iterator iter = icon_paths.begin();
+ for (std::vector<std::string>::const_iterator iter = icon_paths.begin();
iter != icon_paths.end(); ++iter) {
- FilePath path = *iter;
+ FilePath path = extension->GetResourcePath(*iter);
file_loop->PostTask(FROM_HERE, new LoadImageTask(tracker_, path, index++));
}
}
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index da0330b..4940ed2 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1705,6 +1705,7 @@
'browser/views/edit_search_engine_dialog.h',
'browser/views/event_utils.cc',
'browser/views/event_utils.h',
+ 'browser/views/extensions/extension_install_prompt.cc',
'browser/views/extensions/extension_shelf.cc',
'browser/views/extensions/extension_shelf.h',
'browser/views/extensions/extension_view.cc',
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index c92223d..719f61c 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -78,7 +78,12 @@ const size_t Extension::kIdSize = 16;
const char Extension::kMimeType[] = "application/x-chrome-extension";
-const int Extension::kKnownIconSizes[] = { 128 };
+const int Extension::kIconSizes[] = {
+ EXTENSION_ICON_LARGE,
+ EXTENSION_ICON_MEDIUM,
+ EXTENSION_ICON_SMALL,
+ EXTENSION_ICON_BITTY
+};
Extension::~Extension() {
for (PageActionMap::iterator i = page_actions_.begin();
@@ -302,7 +307,7 @@ PageAction* Extension::LoadPageActionHelper(
int icon_count = 0;
for (ListValue::const_iterator iter = icons->begin();
iter != icons->end(); ++iter) {
- FilePath::StringType path;
+ std::string path;
if (!(*iter)->GetAsString(&path) || path.empty()) {
*error = ExtensionErrorUtils::FormatErrorMessage(
errors::kInvalidPageActionIconPath,
@@ -310,8 +315,7 @@ PageAction* Extension::LoadPageActionHelper(
return NULL;
}
- FilePath icon_path = path_.Append(path);
- result->AddIconPath(icon_path);
+ result->AddIconPath(path);
++icon_count;
}
@@ -580,8 +584,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id,
return false;
}
- for (size_t i = 0; i < arraysize(kKnownIconSizes); ++i) {
- std::wstring key = ASCIIToWide(IntToString(kKnownIconSizes[i]));
+ for (size_t i = 0; i < arraysize(kIconSizes); ++i) {
+ std::wstring key = ASCIIToWide(IntToString(kIconSizes[i]));
if (icons_value->HasKey(key)) {
std::string icon_path;
if (!icons_value->GetString(key, &icon_path)) {
@@ -589,7 +593,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id,
errors::kInvalidIconPath, WideToASCII(key));
return false;
}
- icons_[kKnownIconSizes[i]] = icon_path;
+ icons_[kIconSizes[i]] = icon_path;
}
}
}
@@ -914,10 +918,10 @@ std::set<FilePath> Extension::GetBrowserImages() {
// page action icons
for (PageActionMap::const_iterator it = page_actions().begin();
it != page_actions().end(); ++it) {
- const std::vector<FilePath>& icon_paths = it->second->icon_paths();
- for (std::vector<FilePath>::const_iterator iter = icon_paths.begin();
+ const std::vector<std::string>& icon_paths = it->second->icon_paths();
+ for (std::vector<std::string>::const_iterator iter = icon_paths.begin();
iter != icon_paths.end(); ++iter) {
- image_paths.insert(*iter);
+ image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(*iter)));
}
}
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 0571792..550fbba 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -46,8 +46,17 @@ class Extension {
NEW_INSTALL
};
+ // NOTE: If you change this list, you should also change kIconSizes in the cc
+ // file.
+ enum Icons {
+ EXTENSION_ICON_LARGE = 128,
+ EXTENSION_ICON_MEDIUM = 48,
+ EXTENSION_ICON_SMALL = 32,
+ EXTENSION_ICON_BITTY = 16,
+ };
+
// Icon sizes used by the extension system.
- static const int kKnownIconSizes[];
+ static const int kIconSizes[];
// An NPAPI plugin included in the extension.
struct PluginInfo {
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index a33f40c..6eba35a 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -279,8 +279,8 @@ TEST(ExtensionTest, LoadPageActionHelper) {
// Now setup some values to use in the page action.
const std::string id("MyPageActionId");
const std::string name("MyPageActionName");
- FilePath::StringType img1 = FILE_PATH_LITERAL("image1.png");
- FilePath::StringType img2 = FILE_PATH_LITERAL("image2.png");
+ std::string img1("image1.png");
+ std::string img2("image2.png");
// Add the page_actions dictionary.
input.SetString(keys::kPageActionId, id);
@@ -297,8 +297,8 @@ TEST(ExtensionTest, LoadPageActionHelper) {
ASSERT_STREQ(id.c_str(), page_action->id().c_str());
ASSERT_STREQ(name.c_str(), page_action->name().c_str());
ASSERT_EQ(2u, page_action->icon_paths().size());
- ASSERT_STREQ(img1.c_str(), page_action->icon_paths()[0].value().c_str());
- ASSERT_STREQ(img2.c_str(), page_action->icon_paths()[1].value().c_str());
+ ASSERT_STREQ(img1.c_str(), page_action->icon_paths()[0].c_str());
+ ASSERT_STREQ(img2.c_str(), page_action->icon_paths()[1].c_str());
// Type hasn't been set, but it defaults to PERMANENT.
ASSERT_EQ(PageAction::PERMANENT, page_action->type());
diff --git a/chrome/common/page_action.h b/chrome/common/page_action.h
index 7a68eef..31a7c3d 100644
--- a/chrome/common/page_action.h
+++ b/chrome/common/page_action.h
@@ -9,7 +9,7 @@
#include <string>
#include <vector>
-#include "base/file_path.h"
+#include "base/basictypes.h"
class PageAction {
public:
@@ -35,8 +35,8 @@ class PageAction {
std::string name() const { return name_; }
void set_name(const std::string& name) { name_ = name; }
- const std::vector<FilePath>& icon_paths() const { return icon_paths_; }
- void AddIconPath(const FilePath& icon_path) {
+ const std::vector<std::string>& icon_paths() const { return icon_paths_; }
+ void AddIconPath(const std::string& icon_path) {
icon_paths_.push_back(icon_path);
}
@@ -55,7 +55,7 @@ class PageAction {
std::string name_;
// The paths to the icons that this PageIcon can show.
- std::vector<FilePath> icon_paths_;
+ std::vector<std::string> icon_paths_;
};
typedef std::map<std::string, PageAction*> PageActionMap;