OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/extensions/bundle_installer.h" |
| 6 |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
| 10 #include "base/command_line.h" |
| 11 #include "base/values.h" |
| 12 #include "chrome/browser/extensions/crx_installer.h" |
| 13 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/ui/browser.h" |
| 15 #include "chrome/common/chrome_switches.h" |
| 16 #include "content/public/browser/browser_thread.h" |
| 17 #include "content/public/browser/navigation_controller.h" |
| 18 #include "content/public/browser/web_contents.h" |
| 19 |
| 20 using content::NavigationController; |
| 21 |
| 22 namespace extensions { |
| 23 |
| 24 namespace { |
| 25 |
| 26 enum AutoApproveForTest { |
| 27 DO_NOT_SKIP = 0, |
| 28 PROCEED, |
| 29 ABORT |
| 30 }; |
| 31 |
| 32 AutoApproveForTest g_auto_approve_for_test = DO_NOT_SKIP; |
| 33 |
| 34 // Creates a dummy extension and sets the manifest's name to the item's |
| 35 // localized name. |
| 36 scoped_refptr<Extension> CreateDummyExtension(BundleInstaller::Item item, |
| 37 DictionaryValue* manifest) { |
| 38 // We require localized names so we can have nice error messages when we can't |
| 39 // parse an extension manifest. |
| 40 CHECK(!item.localized_name.empty()); |
| 41 |
| 42 manifest->SetString(extension_manifest_keys::kName, item.localized_name); |
| 43 |
| 44 std::string error; |
| 45 return Extension::Create(FilePath(), |
| 46 Extension::INTERNAL, |
| 47 *manifest, |
| 48 Extension::NO_FLAGS, |
| 49 item.id, |
| 50 &error); |
| 51 } |
| 52 |
| 53 } // namespace |
| 54 |
| 55 // static |
| 56 void BundleInstaller::SetAutoApproveForTesting(bool auto_approve) { |
| 57 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)); |
| 58 g_auto_approve_for_test = auto_approve ? PROCEED : ABORT; |
| 59 } |
| 60 |
| 61 BundleInstaller::Item::Item() : state(STATE_PENDING) {} |
| 62 |
| 63 BundleInstaller::BundleInstaller(Profile* profile, |
| 64 const BundleInstaller::ItemList& items) |
| 65 : approved_(false), |
| 66 browser_(NULL), |
| 67 profile_(profile), |
| 68 delegate_(NULL) { |
| 69 BrowserList::AddObserver(this); |
| 70 for (size_t i = 0; i < items.size(); ++i) { |
| 71 items_[items[i].id] = items[i]; |
| 72 items_[items[i].id].state = Item::STATE_PENDING; |
| 73 } |
| 74 } |
| 75 |
| 76 BundleInstaller::~BundleInstaller() { |
| 77 BrowserList::RemoveObserver(this); |
| 78 } |
| 79 |
| 80 BundleInstaller::ItemList BundleInstaller::GetItemsWithState( |
| 81 Item::State state) const { |
| 82 ItemList list; |
| 83 |
| 84 for (ItemMap::const_iterator i = items_.begin(); i != items_.end(); ++i) { |
| 85 if (i->second.state == state) |
| 86 list.push_back(i->second); |
| 87 } |
| 88 |
| 89 return list; |
| 90 } |
| 91 |
| 92 void BundleInstaller::PromptForApproval(Delegate* delegate) { |
| 93 delegate_ = delegate; |
| 94 |
| 95 AddRef(); // Balanced in ReportApproved() and ReportCanceled(). |
| 96 |
| 97 ParseManifests(); |
| 98 } |
| 99 |
| 100 void BundleInstaller::CompleteInstall(NavigationController* controller, |
| 101 Browser* browser, |
| 102 Delegate* delegate) { |
| 103 CHECK(approved_); |
| 104 |
| 105 browser_ = browser; |
| 106 delegate_ = delegate; |
| 107 |
| 108 AddRef(); // Balanced in ReportComplete(); |
| 109 |
| 110 if (GetItemsWithState(Item::STATE_PENDING).empty()) { |
| 111 ReportComplete(); |
| 112 return; |
| 113 } |
| 114 |
| 115 // Start each WebstoreInstaller. |
| 116 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) { |
| 117 if (i->second.state != Item::STATE_PENDING) |
| 118 continue; |
| 119 |
| 120 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller( |
| 121 profile_, |
| 122 this, |
| 123 controller, |
| 124 i->first, |
| 125 WebstoreInstaller::FLAG_NONE); |
| 126 installer->Start(); |
| 127 } |
| 128 } |
| 129 |
| 130 // static |
| 131 void BundleInstaller::ShowInstalledBubble( |
| 132 const BundleInstaller* bundle, Browser* browser) { |
| 133 // TODO(jstritar): provide platform specific implementations. |
| 134 } |
| 135 |
| 136 void BundleInstaller::ParseManifests() { |
| 137 if (items_.empty()) { |
| 138 ReportCanceled(false); |
| 139 return; |
| 140 } |
| 141 |
| 142 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) { |
| 143 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( |
| 144 this, i->first, i->second.manifest, "", GURL(), NULL); |
| 145 helper->Start(); |
| 146 } |
| 147 } |
| 148 |
| 149 void BundleInstaller::ReportApproved() { |
| 150 if (delegate_) |
| 151 delegate_->OnBundleInstallApproved(); |
| 152 |
| 153 Release(); // Balanced in PromptForApproval(). |
| 154 } |
| 155 |
| 156 void BundleInstaller::ReportCanceled(bool user_initiated) { |
| 157 if (delegate_) |
| 158 delegate_->OnBundleInstallCanceled(user_initiated); |
| 159 |
| 160 Release(); // Balanced in PromptForApproval(). |
| 161 } |
| 162 |
| 163 void BundleInstaller::ReportComplete() { |
| 164 if (delegate_) |
| 165 delegate_->OnBundleInstallCompleted(); |
| 166 |
| 167 Release(); // Balanced in CompleteInstall(). |
| 168 } |
| 169 |
| 170 void BundleInstaller::ShowPromptIfDoneParsing() { |
| 171 // We don't prompt until all the manifests have been parsed. |
| 172 ItemList pending_items = GetItemsWithState(Item::STATE_PENDING); |
| 173 if (pending_items.size() != dummy_extensions_.size()) |
| 174 return; |
| 175 |
| 176 ShowPrompt(); |
| 177 } |
| 178 |
| 179 void BundleInstaller::ShowPrompt() { |
| 180 // Abort if we couldn't create any Extensions out of the manifests. |
| 181 if (dummy_extensions_.empty()) { |
| 182 ReportCanceled(false); |
| 183 return; |
| 184 } |
| 185 |
| 186 scoped_refptr<ExtensionPermissionSet> permissions; |
| 187 for (size_t i = 0; i < dummy_extensions_.size(); ++i) { |
| 188 permissions = ExtensionPermissionSet::CreateUnion( |
| 189 permissions, dummy_extensions_[i]->required_permission_set()); |
| 190 } |
| 191 |
| 192 // TODO(jstritar): show the actual prompt. |
| 193 if (g_auto_approve_for_test == PROCEED) |
| 194 InstallUIProceed(); |
| 195 else if (g_auto_approve_for_test == ABORT) |
| 196 InstallUIAbort(true); |
| 197 else |
| 198 InstallUIAbort(false); |
| 199 } |
| 200 |
| 201 void BundleInstaller::ShowInstalledBubbleIfDone() { |
| 202 // We're ready to show the installed bubble when no items are pending. |
| 203 if (!GetItemsWithState(Item::STATE_PENDING).empty()) |
| 204 return; |
| 205 |
| 206 if (browser_) |
| 207 ShowInstalledBubble(this, browser_); |
| 208 |
| 209 ReportComplete(); |
| 210 } |
| 211 |
| 212 void BundleInstaller::OnWebstoreParseSuccess( |
| 213 const std::string& id, |
| 214 const SkBitmap& icon, |
| 215 DictionaryValue* manifest) { |
| 216 dummy_extensions_.push_back(CreateDummyExtension(items_[id], manifest)); |
| 217 parsed_manifests_[id] = linked_ptr<DictionaryValue>(manifest); |
| 218 |
| 219 ShowPromptIfDoneParsing(); |
| 220 } |
| 221 |
| 222 void BundleInstaller::OnWebstoreParseFailure( |
| 223 const std::string& id, |
| 224 WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code, |
| 225 const std::string& error_message) { |
| 226 items_[id].state = Item::STATE_FAILED; |
| 227 |
| 228 ShowPromptIfDoneParsing(); |
| 229 } |
| 230 |
| 231 void BundleInstaller::InstallUIProceed() { |
| 232 approved_ = true; |
| 233 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) { |
| 234 if (i->second.state != Item::STATE_PENDING) |
| 235 continue; |
| 236 |
| 237 // Create a whitelist entry for each of the approved extensions. |
| 238 CrxInstaller::WhitelistEntry* entry = new CrxInstaller::WhitelistEntry; |
| 239 entry->parsed_manifest.reset(parsed_manifests_[i->first]->DeepCopy()); |
| 240 entry->localized_name = i->second.localized_name; |
| 241 entry->use_app_installed_bubble = false; |
| 242 entry->skip_post_install_ui = true; |
| 243 CrxInstaller::SetWhitelistEntry(i->first, entry); |
| 244 } |
| 245 ReportApproved(); |
| 246 } |
| 247 |
| 248 void BundleInstaller::InstallUIAbort(bool user_initiated) { |
| 249 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) |
| 250 i->second.state = Item::STATE_FAILED; |
| 251 |
| 252 ReportCanceled(user_initiated); |
| 253 } |
| 254 |
| 255 void BundleInstaller::OnExtensionInstallSuccess(const std::string& id) { |
| 256 items_[id].state = Item::STATE_INSTALLED; |
| 257 |
| 258 ShowInstalledBubbleIfDone(); |
| 259 } |
| 260 |
| 261 void BundleInstaller::OnExtensionInstallFailure(const std::string& id, |
| 262 const std::string& error) { |
| 263 items_[id].state = Item::STATE_FAILED; |
| 264 |
| 265 ShowInstalledBubbleIfDone(); |
| 266 } |
| 267 |
| 268 void BundleInstaller::OnBrowserAdded(const Browser* browser) { |
| 269 } |
| 270 |
| 271 void BundleInstaller::OnBrowserRemoved(const Browser* browser) { |
| 272 if (browser_ == browser) |
| 273 browser_ = NULL; |
| 274 } |
| 275 |
| 276 void BundleInstaller::OnBrowserSetLastActive(const Browser* browser) { |
| 277 } |
| 278 |
| 279 } // namespace extensions |
OLD | NEW |