Chromium Code Reviews| Index: chrome/browser/extensions/api/webstore/bundle_installer.cc |
| diff --git a/chrome/browser/extensions/api/webstore/bundle_installer.cc b/chrome/browser/extensions/api/webstore/bundle_installer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7ed0895a2709c3cad06d24892911d5b6c9404faf |
| --- /dev/null |
| +++ b/chrome/browser/extensions/api/webstore/bundle_installer.cc |
| @@ -0,0 +1,262 @@ |
| +// Copyright (c) 2011 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/api/webstore/bundle_installer.h" |
| + |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "base/stl_util.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/browser/ui/browser_list.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 webstore { |
| + |
| +namespace { |
| + |
| +enum AutoApproveForTest { |
| + DO_NOT_SKIP = 0, |
| + PROCEED, |
| + ABORT |
| +}; |
| + |
| +AutoApproveForTest auto_approve_for_test = DO_NOT_SKIP; |
|
Aaron Boodman
2012/02/17 01:59:33
g_auto_approve...
jstritar
2012/02/17 22:29:09
Done.
|
| + |
| +} // namespace |
| + |
| +// static |
| +void BundleInstaller::SetAutoApproveForTesting(bool auto_approve) { |
| + auto_approve_for_test = auto_approve ? PROCEED : ABORT; |
| +} |
| + |
| +scoped_refptr<Extension> Item::CreateDummyExtension(DictionaryValue* manifest) { |
| + // We require localized names so we can have nice error messages when we can't |
| + // parse an extension manifest. |
| + CHECK(!localized_name.empty()); |
| + |
| + manifest->SetString(extension_manifest_keys::kName, localized_name); |
| + |
| + std::string error; |
| + return Extension::Create( |
|
Aaron Boodman
2012/02/17 01:59:33
You can move the arguments up one line.
jstritar
2012/02/17 22:29:09
Done.
|
| + FilePath(), |
| + Extension::INTERNAL, |
| + *manifest, |
| + Extension::NO_FLAGS, |
| + id, |
| + &error); |
| +} |
| + |
| +BundleInstaller::BundleInstaller(Profile* profile, const ItemList& items) |
| + : profile_(profile), |
|
Aaron Boodman
2012/02/17 01:59:33
You need to initialize approved_ too.
jstritar
2012/02/17 22:29:09
Done.
|
| + controller_(NULL), |
| + delegate_(NULL) { |
| + for (size_t i = 0; i < items.size(); ++i) |
| + pending_items_[items[i].id] = items[i]; |
| +} |
| + |
| +BundleInstaller::~BundleInstaller() { |
| + STLDeleteContainerPairSecondPointers( |
|
Aaron Boodman
2012/02/17 01:59:33
You can just make the map be: std::map<int, linked
jstritar
2012/02/17 22:29:09
Nice, do you pretty much only use linked_ptrs in S
Aaron Boodman
2012/02/18 11:11:54
Yeah, I don't really know of any use for them othe
|
| + parsed_manifests_.begin(), parsed_manifests_.end()); |
| +} |
| + |
| +ItemList BundleInstaller::GetInstalledItems() const { |
| + return GetItemMapAsList(installed_items_); |
| +} |
| + |
| +ItemList BundleInstaller::GetFailedItems() const { |
| + return GetItemMapAsList(failed_items_); |
| +} |
| + |
| +void BundleInstaller::PromptForApproval(Delegate* delegate) { |
| + delegate_ = delegate; |
| + |
| + AddRef(); // Balanced in ReportApproved() and ReportCanceled(). |
| + |
| + ParseManifests(); |
| +} |
| + |
| +void BundleInstaller::CompleteInstall(NavigationController* controller, |
| + Delegate* delegate) { |
| + controller_ = controller; |
| + delegate_ = delegate; |
| + |
| + AddRef(); // Balanced in ReportComplete(); |
| + |
| + if (!approved_ || pending_items_.empty()) { |
| + ReportComplete(); |
| + return; |
| + } |
| + |
| + // Start each WebstoreInstaller. |
| + for (ItemMap::iterator i = pending_items_.begin(); |
| + i != pending_items_.end(); ++i) { |
| + scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller( |
| + profile_, |
| + this, |
| + controller_, |
| + i->first, |
| + WebstoreInstaller::FLAG_NONE); |
| + installer->Start(); |
| + } |
| +} |
| + |
| +void BundleInstaller::ReportApproved() { |
| + if (delegate_) |
| + delegate_->OnBundleInstallApproved(); |
| + |
| + Release(); // Balanced in ParseManifests(). |
| +} |
| + |
| +void BundleInstaller::ReportCanceled(bool user_initiated) { |
| + if (delegate_) |
| + delegate_->OnBundleInstallCanceled(user_initiated); |
| + |
| + Release(); // Balanced in ParseManifests(). |
| +} |
| + |
| +void BundleInstaller::ReportComplete() { |
| + if (delegate_) |
| + delegate_->OnBundleInstallCompleted(); |
| + |
| + Release(); // Balanced in CompleteInstall(). |
| +} |
| + |
| +void BundleInstaller::OnWebstoreParseSuccess( |
| + const std::string& id, |
| + const SkBitmap& icon, |
| + DictionaryValue* manifest) { |
| + dummy_extensions_.push_back( |
| + pending_items_[id].CreateDummyExtension(manifest)); |
| + parsed_manifests_[id] = manifest; |
| + |
| + ShowPromptIfDoneParsing(); |
| +} |
| + |
| +void BundleInstaller::OnWebstoreParseFailure( |
| + const std::string& id, |
| + WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code, |
| + const std::string& error_message) { |
| + failed_items_[id] = pending_items_[id]; |
| + pending_items_.erase(id); |
| + |
| + ShowPromptIfDoneParsing(); |
| +} |
| + |
| +void BundleInstaller::InstallUIProceed() { |
| + approved_ = true; |
| + for (ItemMap::iterator i = pending_items_.begin(); |
| + i != pending_items_.end(); ++i) { |
| + // 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) { |
| + failed_items_.insert(pending_items_.begin(), pending_items_.end()); |
| + pending_items_.clear(); |
| + |
| + ReportCanceled(user_initiated); |
| +} |
| + |
| +void BundleInstaller::OnExtensionInstallSuccess(const std::string& id) { |
| + installed_items_[id] = pending_items_[id]; |
| + pending_items_.erase(id); |
|
Aaron Boodman
2012/02/17 01:59:33
Instead of moving things between lists this way, c
jstritar
2012/02/17 22:29:09
Done.
|
| + |
| + ShowInstalledBubbleIfDone(); |
| +} |
| + |
| +void BundleInstaller::OnExtensionInstallFailure(const std::string& id, |
| + const std::string& error) { |
| + failed_items_[id] = pending_items_[id]; |
| + pending_items_.erase(id); |
| + |
| + ShowInstalledBubbleIfDone(); |
| +} |
| + |
| +ItemList BundleInstaller::GetItemMapAsList( |
| + const BundleInstaller::ItemMap& item_map) { |
| + ItemList list; |
| + |
| + for (ItemMap::const_iterator i = item_map.begin(); i != item_map.end(); ++i) |
| + list.push_back(i->second); |
| + |
| + return list; |
| +} |
| + |
| +// static |
| +void BundleInstaller::ShowInstalledBubble( |
| + const BundleInstaller* bundle, Browser* browser) { |
| + // TODO(jstritar): provide platform specific implementations. |
| +} |
| + |
| +void BundleInstaller::ParseManifests() { |
|
Aaron Boodman
2012/02/17 01:59:33
I think it would be easier to read if you put the
jstritar
2012/02/17 22:29:09
Done.
|
| + if (pending_items_.empty()) { |
| + ReportCanceled(false); |
| + return; |
| + } |
| + |
| + for (ItemMap::iterator i = pending_items_.begin(); |
| + i != pending_items_.end(); ++i) { |
| + scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( |
| + this, i->first, i->second.manifest, "", GURL(), NULL); |
| + helper->Start(); |
| + } |
| +} |
| + |
| +void BundleInstaller::ShowPromptIfDoneParsing() { |
| + // We don't prompt until all the manifests have been parsed. |
| + if (pending_items_.size() != dummy_extensions_.size()) |
| + return; |
| + |
| + ShowPrompt(); |
| +} |
| + |
| +void BundleInstaller::ShowPrompt() { |
| + if (pending_items_.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 (auto_approve_for_test == PROCEED) |
| + InstallUIProceed(); |
| + else if (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 (!pending_items_.empty()) |
| + return; |
| + |
| + Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); |
|
Aaron Boodman
2012/02/17 01:59:33
It seems that it would be better to pass a Browser
jstritar
2012/02/17 22:29:09
Done. Went with a Browser (rather than TabContents
|
| + if (browser) |
| + ShowInstalledBubble(this, browser); |
| + |
| + ReportComplete(); |
| +} |
| + |
| +} // namespace webstore |