summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/bundle_installer.cc
diff options
context:
space:
mode:
authorjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-23 16:27:57 +0000
committerjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-23 16:27:57 +0000
commitbc070bfbee2eb7a8188712d2b988719ab55fbb48 (patch)
treed3e3c055d3f3458a0fbcbe0061855c975bc9cf35 /chrome/browser/extensions/bundle_installer.cc
parent6916dcd5ddfc3c6c126f8ded62799a55c6868ba2 (diff)
downloadchromium_src-bc070bfbee2eb7a8188712d2b988719ab55fbb48.zip
chromium_src-bc070bfbee2eb7a8188712d2b988719ab55fbb48.tar.gz
chromium_src-bc070bfbee2eb7a8188712d2b988719ab55fbb48.tar.bz2
Add a webstore API for installing bundles of extensions.
This does not include any of the UI. Re-landing due to trouble on debug bots (parameters section was missing from the callback spec). BUG=112096 TEST=*InstallBundle* Review URL: https://chromiumcodereview.appspot.com/9414013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123253 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions/bundle_installer.cc')
-rw-r--r--chrome/browser/extensions/bundle_installer.cc279
1 files changed, 279 insertions, 0 deletions
diff --git a/chrome/browser/extensions/bundle_installer.cc b/chrome/browser/extensions/bundle_installer.cc
new file mode 100644
index 0000000..8772b0b
--- /dev/null
+++ b/chrome/browser/extensions/bundle_installer.cc
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 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 "chrome/browser/extensions/bundle_installer.h"
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/web_contents.h"
+
+using content::NavigationController;
+
+namespace extensions {
+
+namespace {
+
+enum AutoApproveForTest {
+ DO_NOT_SKIP = 0,
+ PROCEED,
+ ABORT
+};
+
+AutoApproveForTest g_auto_approve_for_test = DO_NOT_SKIP;
+
+// Creates a dummy extension and sets the manifest's name to the item's
+// localized name.
+scoped_refptr<Extension> CreateDummyExtension(BundleInstaller::Item item,
+ DictionaryValue* manifest) {
+ // We require localized names so we can have nice error messages when we can't
+ // parse an extension manifest.
+ CHECK(!item.localized_name.empty());
+
+ manifest->SetString(extension_manifest_keys::kName, item.localized_name);
+
+ std::string error;
+ return Extension::Create(FilePath(),
+ Extension::INTERNAL,
+ *manifest,
+ Extension::NO_FLAGS,
+ item.id,
+ &error);
+}
+
+} // namespace
+
+// static
+void BundleInstaller::SetAutoApproveForTesting(bool auto_approve) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType));
+ g_auto_approve_for_test = auto_approve ? PROCEED : ABORT;
+}
+
+BundleInstaller::Item::Item() : state(STATE_PENDING) {}
+
+BundleInstaller::BundleInstaller(Profile* profile,
+ const BundleInstaller::ItemList& items)
+ : approved_(false),
+ browser_(NULL),
+ profile_(profile),
+ delegate_(NULL) {
+ BrowserList::AddObserver(this);
+ for (size_t i = 0; i < items.size(); ++i) {
+ items_[items[i].id] = items[i];
+ items_[items[i].id].state = Item::STATE_PENDING;
+ }
+}
+
+BundleInstaller::~BundleInstaller() {
+ BrowserList::RemoveObserver(this);
+}
+
+BundleInstaller::ItemList BundleInstaller::GetItemsWithState(
+ Item::State state) const {
+ ItemList list;
+
+ for (ItemMap::const_iterator i = items_.begin(); i != items_.end(); ++i) {
+ if (i->second.state == state)
+ list.push_back(i->second);
+ }
+
+ return list;
+}
+
+void BundleInstaller::PromptForApproval(Delegate* delegate) {
+ delegate_ = delegate;
+
+ AddRef(); // Balanced in ReportApproved() and ReportCanceled().
+
+ ParseManifests();
+}
+
+void BundleInstaller::CompleteInstall(NavigationController* controller,
+ Browser* browser,
+ Delegate* delegate) {
+ CHECK(approved_);
+
+ browser_ = browser;
+ delegate_ = delegate;
+
+ AddRef(); // Balanced in ReportComplete();
+
+ if (GetItemsWithState(Item::STATE_PENDING).empty()) {
+ ReportComplete();
+ return;
+ }
+
+ // Start each WebstoreInstaller.
+ for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) {
+ if (i->second.state != Item::STATE_PENDING)
+ continue;
+
+ scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
+ profile_,
+ this,
+ controller,
+ i->first,
+ WebstoreInstaller::FLAG_NONE);
+ installer->Start();
+ }
+}
+
+// static
+void BundleInstaller::ShowInstalledBubble(
+ const BundleInstaller* bundle, Browser* browser) {
+ // TODO(jstritar): provide platform specific implementations.
+}
+
+void BundleInstaller::ParseManifests() {
+ if (items_.empty()) {
+ ReportCanceled(false);
+ return;
+ }
+
+ for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) {
+ scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
+ this, i->first, i->second.manifest, "", GURL(), NULL);
+ helper->Start();
+ }
+}
+
+void BundleInstaller::ReportApproved() {
+ if (delegate_)
+ delegate_->OnBundleInstallApproved();
+
+ Release(); // Balanced in PromptForApproval().
+}
+
+void BundleInstaller::ReportCanceled(bool user_initiated) {
+ if (delegate_)
+ delegate_->OnBundleInstallCanceled(user_initiated);
+
+ Release(); // Balanced in PromptForApproval().
+}
+
+void BundleInstaller::ReportComplete() {
+ if (delegate_)
+ delegate_->OnBundleInstallCompleted();
+
+ Release(); // Balanced in CompleteInstall().
+}
+
+void BundleInstaller::ShowPromptIfDoneParsing() {
+ // We don't prompt until all the manifests have been parsed.
+ ItemList pending_items = GetItemsWithState(Item::STATE_PENDING);
+ if (pending_items.size() != dummy_extensions_.size())
+ return;
+
+ ShowPrompt();
+}
+
+void BundleInstaller::ShowPrompt() {
+ // Abort if we couldn't create any Extensions out of the manifests.
+ if (dummy_extensions_.empty()) {
+ ReportCanceled(false);
+ return;
+ }
+
+ scoped_refptr<ExtensionPermissionSet> permissions;
+ for (size_t i = 0; i < dummy_extensions_.size(); ++i) {
+ permissions = ExtensionPermissionSet::CreateUnion(
+ permissions, dummy_extensions_[i]->required_permission_set());
+ }
+
+ // TODO(jstritar): show the actual prompt.
+ if (g_auto_approve_for_test == PROCEED)
+ InstallUIProceed();
+ else if (g_auto_approve_for_test == ABORT)
+ InstallUIAbort(true);
+ else
+ InstallUIAbort(false);
+}
+
+void BundleInstaller::ShowInstalledBubbleIfDone() {
+ // We're ready to show the installed bubble when no items are pending.
+ if (!GetItemsWithState(Item::STATE_PENDING).empty())
+ return;
+
+ if (browser_)
+ ShowInstalledBubble(this, browser_);
+
+ ReportComplete();
+}
+
+void BundleInstaller::OnWebstoreParseSuccess(
+ const std::string& id,
+ const SkBitmap& icon,
+ DictionaryValue* manifest) {
+ dummy_extensions_.push_back(CreateDummyExtension(items_[id], manifest));
+ parsed_manifests_[id] = linked_ptr<DictionaryValue>(manifest);
+
+ ShowPromptIfDoneParsing();
+}
+
+void BundleInstaller::OnWebstoreParseFailure(
+ const std::string& id,
+ WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code,
+ const std::string& error_message) {
+ items_[id].state = Item::STATE_FAILED;
+
+ ShowPromptIfDoneParsing();
+}
+
+void BundleInstaller::InstallUIProceed() {
+ approved_ = true;
+ for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) {
+ if (i->second.state != Item::STATE_PENDING)
+ continue;
+
+ // Create a whitelist entry for each of the approved extensions.
+ CrxInstaller::WhitelistEntry* entry = new CrxInstaller::WhitelistEntry;
+ entry->parsed_manifest.reset(parsed_manifests_[i->first]->DeepCopy());
+ entry->localized_name = i->second.localized_name;
+ entry->use_app_installed_bubble = false;
+ entry->skip_post_install_ui = true;
+ CrxInstaller::SetWhitelistEntry(i->first, entry);
+ }
+ ReportApproved();
+}
+
+void BundleInstaller::InstallUIAbort(bool user_initiated) {
+ for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i)
+ i->second.state = Item::STATE_FAILED;
+
+ ReportCanceled(user_initiated);
+}
+
+void BundleInstaller::OnExtensionInstallSuccess(const std::string& id) {
+ items_[id].state = Item::STATE_INSTALLED;
+
+ ShowInstalledBubbleIfDone();
+}
+
+void BundleInstaller::OnExtensionInstallFailure(const std::string& id,
+ const std::string& error) {
+ items_[id].state = Item::STATE_FAILED;
+
+ ShowInstalledBubbleIfDone();
+}
+
+void BundleInstaller::OnBrowserAdded(const Browser* browser) {
+}
+
+void BundleInstaller::OnBrowserRemoved(const Browser* browser) {
+ if (browser_ == browser)
+ browser_ = NULL;
+}
+
+void BundleInstaller::OnBrowserSetLastActive(const Browser* browser) {
+}
+
+} // namespace extensions