blob: 859cf48067c0ff3161a98ef25739f088b57bd2b3 [file] [log] [blame]
[email protected]bdb74a22012-01-25 20:33:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8915f342011-08-29 22:14:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]734bcec2012-10-08 20:29:055#include "chrome/browser/extensions/webstore_standalone_installer.h"
[email protected]8915f342011-08-29 22:14:376
[email protected]8915f342011-08-29 22:14:377#include "base/values.h"
[email protected]9c7b3092014-06-21 01:19:038#include "base/version.h"
[email protected]8915f342011-08-29 22:14:379#include "chrome/browser/extensions/crx_installer.h"
[email protected]d44ec7b2013-03-15 04:34:3410#include "chrome/browser/extensions/extension_install_prompt.h"
[email protected]00b38242012-07-18 18:43:2211#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]453ac122014-07-28 03:32:1312#include "chrome/browser/extensions/extension_install_ui_util.h"
[email protected]655b2b1a2011-10-13 17:13:0613#include "chrome/browser/extensions/extension_service.h"
[email protected]773272b2014-07-18 05:48:3514#include "chrome/browser/extensions/install_tracker.h"
[email protected]7b3941052013-02-13 01:21:5915#include "chrome/browser/extensions/webstore_data_fetcher.h"
[email protected]8915f342011-08-29 22:14:3716#include "chrome/browser/profiles/profile.h"
[email protected]10c2d692012-05-11 05:32:2317#include "content/public/browser/web_contents.h"
[email protected]489db0842014-01-22 18:20:0318#include "extensions/browser/extension_prefs.h"
[email protected]760f743b2014-05-28 13:52:0219#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2420#include "extensions/browser/extension_system.h"
[email protected]411f8ae2014-05-22 11:12:2321#include "extensions/browser/extension_util.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]a6483d22013-07-03 22:11:0023#include "url/gurl.h"
[email protected]8915f342011-08-29 22:14:3724
[email protected]26b5e322011-12-23 01:36:4725using content::WebContents;
[email protected]631bb742011-11-02 11:29:3926
[email protected]3d61a7f2012-07-12 19:11:2527namespace extensions {
28
[email protected]a221ef092011-09-07 01:34:1029const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
30const char kWebstoreRequestError[] =
31 "Could not fetch data from the Chrome Web Store";
32const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
[email protected]8915f342011-08-29 22:14:3733const char kInvalidManifestError[] = "Invalid manifest";
34const char kUserCancelledError[] = "User cancelled install";
[email protected]f6b88d92014-01-09 19:45:3435const char kExtensionIsBlacklisted[] = "Extension is blacklisted";
[email protected]773272b2014-07-18 05:48:3536const char kInstallInProgressError[] = "An install is already in progress";
37const char kLaunchInProgressError[] = "A launch is already in progress";
[email protected]8915f342011-08-29 22:14:3738
[email protected]734bcec2012-10-08 20:29:0539WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
[email protected]d44ec7b2013-03-15 04:34:3440 const std::string& webstore_item_id,
[email protected]c1b2d042013-02-23 00:31:0441 Profile* profile,
[email protected]c1b2d042013-02-23 00:31:0442 const Callback& callback)
[email protected]d44ec7b2013-03-15 04:34:3443 : id_(webstore_item_id),
[email protected]d2a639e2012-09-17 07:41:2144 callback_(callback),
[email protected]d44ec7b2013-03-15 04:34:3445 profile_(profile),
[email protected]084e35482013-09-25 02:46:1946 install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE),
[email protected]dcde34b32013-07-31 02:28:4547 show_user_count_(true),
[email protected]c7bf7452011-09-12 21:31:5048 average_rating_(0.0),
[email protected]5f2a4752012-04-27 22:18:5849 rating_count_(0) {
[email protected]c1b2d042013-02-23 00:31:0450}
51
[email protected]734bcec2012-10-08 20:29:0552void WebstoreStandaloneInstaller::BeginInstall() {
[email protected]3d6d676522013-10-14 20:44:5553 // Add a ref to keep this alive for WebstoreDataFetcher.
54 // All code paths from here eventually lead to either CompleteInstall or
55 // AbortInstall, which both release this ref.
56 AddRef();
[email protected]8915f342011-08-29 22:14:3757
[email protected]3d61a7f2012-07-12 19:11:2558 if (!Extension::IdIsValid(id_)) {
[email protected]9c7b3092014-06-21 01:19:0359 CompleteInstall(webstore_install::INVALID_ID, kInvalidWebstoreItemId);
[email protected]8915f342011-08-29 22:14:3760 return;
61 }
62
[email protected]ced522c2014-07-23 20:23:5963 webstore_install::Result result = webstore_install::OTHER_ERROR;
[email protected]773272b2014-07-18 05:48:3564 std::string error;
65 if (!EnsureUniqueInstall(&result, &error)) {
66 CompleteInstall(result, error);
67 return;
68 }
69
[email protected]b4574c02011-11-17 06:19:1370 // Use the requesting page as the referrer both since that is more correct
71 // (it is the page that caused this request to happen) and so that we can
72 // track top sites that trigger inline install requests.
[email protected]7b3941052013-02-13 01:21:5973 webstore_data_fetcher_.reset(new WebstoreDataFetcher(
74 this,
[email protected]c1b2d042013-02-23 00:31:0475 profile_->GetRequestContext(),
[email protected]d44ec7b2013-03-15 04:34:3476 GetRequestorURL(),
[email protected]7b3941052013-02-13 01:21:5977 id_));
78 webstore_data_fetcher_->Start();
[email protected]8915f342011-08-29 22:14:3779}
80
[email protected]9c7b3092014-06-21 01:19:0381//
82// Private interface implementation.
83//
84
85WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {
86}
87
88void WebstoreStandaloneInstaller::AbortInstall() {
89 callback_.Reset();
90 // Abort any in-progress fetches.
91 if (webstore_data_fetcher_) {
92 webstore_data_fetcher_.reset();
[email protected]773272b2014-07-18 05:48:3593 scoped_active_install_.reset();
[email protected]9c7b3092014-06-21 01:19:0394 Release(); // Matches the AddRef in BeginInstall.
95 }
96}
97
[email protected]773272b2014-07-18 05:48:3598bool WebstoreStandaloneInstaller::EnsureUniqueInstall(
99 webstore_install::Result* reason,
100 std::string* error) {
101 InstallTracker* tracker = InstallTracker::Get(profile_);
102 DCHECK(tracker);
103
104 const ActiveInstallData* existing_install_data =
105 tracker->GetActiveInstall(id_);
106 if (existing_install_data) {
107 if (existing_install_data->is_ephemeral) {
108 *reason = webstore_install::LAUNCH_IN_PROGRESS;
109 *error = kLaunchInProgressError;
110 } else {
111 *reason = webstore_install::INSTALL_IN_PROGRESS;
112 *error = kInstallInProgressError;
113 }
114 return false;
115 }
116
117 ActiveInstallData install_data(id_);
118 InitInstallData(&install_data);
119 scoped_active_install_.reset(new ScopedActiveInstall(tracker, install_data));
120 return true;
121}
122
[email protected]9c7b3092014-06-21 01:19:03123void WebstoreStandaloneInstaller::CompleteInstall(
124 webstore_install::Result result,
125 const std::string& error) {
[email protected]773272b2014-07-18 05:48:35126 scoped_active_install_.reset();
[email protected]9c7b3092014-06-21 01:19:03127 if (!callback_.is_null())
[email protected]ced522c2014-07-23 20:23:59128 callback_.Run(result == webstore_install::SUCCESS, error, result);
[email protected]9c7b3092014-06-21 01:19:03129 Release(); // Matches the AddRef in BeginInstall.
130}
131
132void WebstoreStandaloneInstaller::ProceedWithInstallPrompt() {
133 install_prompt_ = CreateInstallPrompt();
134 if (install_prompt_) {
135 ShowInstallUI();
136 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
137 } else {
138 InstallUIProceed();
139 }
140}
141
142scoped_refptr<const Extension>
143WebstoreStandaloneInstaller::GetLocalizedExtensionForDisplay() {
144 if (!localized_extension_for_display_.get()) {
145 DCHECK(manifest_.get());
146 if (!manifest_.get())
147 return NULL;
148
149 std::string error;
150 localized_extension_for_display_ =
151 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
152 manifest_.get(),
153 Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
154 id_,
155 localized_name_,
156 localized_description_,
157 &error);
158 }
159 return localized_extension_for_display_.get();
160}
161
[email protected]773272b2014-07-18 05:48:35162void WebstoreStandaloneInstaller::InitInstallData(
163 ActiveInstallData* install_data) const {
164 // Default implementation sets no properties.
165}
166
[email protected]9c7b3092014-06-21 01:19:03167void WebstoreStandaloneInstaller::OnManifestParsed() {
168 ProceedWithInstallPrompt();
[email protected]ce35418b2013-11-25 01:22:33169}
170
[email protected]f8b23b42013-06-27 20:12:14171scoped_ptr<ExtensionInstallPrompt>
172WebstoreStandaloneInstaller::CreateInstallUI() {
173 return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
174}
175
[email protected]ce35418b2013-11-25 01:22:33176scoped_ptr<WebstoreInstaller::Approval>
177WebstoreStandaloneInstaller::CreateApproval() const {
178 scoped_ptr<WebstoreInstaller::Approval> approval(
179 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
180 profile_,
181 id_,
182 scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy()),
183 true));
184 approval->skip_post_install_ui = !ShouldShowPostInstallUI();
185 approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
186 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
187 return approval.Pass();
188}
189
[email protected]7b3941052013-02-13 01:21:59190void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
[email protected]e263a6b62014-06-05 23:19:49191 OnWebStoreDataFetcherDone();
[email protected]9c7b3092014-06-21 01:19:03192 CompleteInstall(webstore_install::WEBSTORE_REQUEST_ERROR,
193 kWebstoreRequestError);
[email protected]8915f342011-08-29 22:14:37194}
195
[email protected]734bcec2012-10-08 20:29:05196void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
[email protected]cb1078de2013-12-23 20:04:22197 scoped_ptr<base::DictionaryValue> webstore_data) {
[email protected]e263a6b62014-06-05 23:19:49198 OnWebStoreDataFetcherDone();
199
[email protected]d44ec7b2013-03-15 04:34:34200 if (!CheckRequestorAlive()) {
[email protected]9c7b3092014-06-21 01:19:03201 CompleteInstall(webstore_install::ABORTED, std::string());
[email protected]4693243e2011-09-09 23:52:37202 return;
203 }
204
[email protected]d44ec7b2013-03-15 04:34:34205 std::string error;
[email protected]8915f342011-08-29 22:14:37206
[email protected]d44ec7b2013-03-15 04:34:34207 if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
[email protected]9c7b3092014-06-21 01:19:03208 CompleteInstall(webstore_install::NOT_PERMITTED, error);
[email protected]8915f342011-08-29 22:14:37209 return;
210 }
211
[email protected]d44ec7b2013-03-15 04:34:34212 if (!CheckRequestorPermitted(*webstore_data, &error)) {
[email protected]9c7b3092014-06-21 01:19:03213 CompleteInstall(webstore_install::NOT_PERMITTED, error);
[email protected]dd5161a2011-09-14 17:40:17214 return;
215 }
216
217 // Manifest, number of users, average rating and rating count are required.
218 std::string manifest;
219 if (!webstore_data->GetString(kManifestKey, &manifest) ||
220 !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
[email protected]5fdbd6f2011-09-01 17:33:04221 !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
222 !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
[email protected]9c7b3092014-06-21 01:19:03223 CompleteInstall(webstore_install::INVALID_WEBSTORE_RESPONSE,
224 kInvalidWebstoreResponseError);
[email protected]5fdbd6f2011-09-01 17:33:04225 return;
226 }
227
[email protected]dcde34b32013-07-31 02:28:45228 // Optional.
229 show_user_count_ = true;
230 webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);
231
[email protected]c82da8c42012-06-08 19:49:11232 if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
233 average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
[email protected]9c7b3092014-06-21 01:19:03234 CompleteInstall(webstore_install::INVALID_WEBSTORE_RESPONSE,
235 kInvalidWebstoreResponseError);
[email protected]5fdbd6f2011-09-01 17:33:04236 return;
237 }
238
239 // Localized name and description are optional.
240 if ((webstore_data->HasKey(kLocalizedNameKey) &&
241 !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
242 (webstore_data->HasKey(kLocalizedDescriptionKey) &&
243 !webstore_data->GetString(
244 kLocalizedDescriptionKey, &localized_description_))) {
[email protected]9c7b3092014-06-21 01:19:03245 CompleteInstall(webstore_install::INVALID_WEBSTORE_RESPONSE,
246 kInvalidWebstoreResponseError);
[email protected]8915f342011-08-29 22:14:37247 return;
248 }
249
250 // Icon URL is optional.
251 GURL icon_url;
252 if (webstore_data->HasKey(kIconUrlKey)) {
253 std::string icon_url_string;
254 if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
[email protected]9c7b3092014-06-21 01:19:03255 CompleteInstall(webstore_install::INVALID_WEBSTORE_RESPONSE,
256 kInvalidWebstoreResponseError);
[email protected]8915f342011-08-29 22:14:37257 return;
258 }
259 icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
260 icon_url_string);
261 if (!icon_url.is_valid()) {
[email protected]9c7b3092014-06-21 01:19:03262 CompleteInstall(webstore_install::INVALID_WEBSTORE_RESPONSE,
263 kInvalidWebstoreResponseError);
[email protected]8915f342011-08-29 22:14:37264 return;
265 }
266 }
267
[email protected]d44ec7b2013-03-15 04:34:34268 // Assume ownership of webstore_data.
[email protected]b3188ec2013-11-06 10:26:13269 webstore_data_ = webstore_data.Pass();
[email protected]a221ef092011-09-07 01:34:10270
[email protected]007b3f82013-04-09 08:46:45271 scoped_refptr<WebstoreInstallHelper> helper =
272 new WebstoreInstallHelper(this,
273 id_,
274 manifest,
275 std::string(), // We don't have any icon data.
276 icon_url,
277 profile_->GetRequestContext());
[email protected]8915f342011-08-29 22:14:37278 // The helper will call us back via OnWebstoreParseSucces or
279 // OnWebstoreParseFailure.
280 helper->Start();
281}
282
[email protected]734bcec2012-10-08 20:29:05283void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
[email protected]8915f342011-08-29 22:14:37284 const std::string& error) {
[email protected]e263a6b62014-06-05 23:19:49285 OnWebStoreDataFetcherDone();
[email protected]9c7b3092014-06-21 01:19:03286 CompleteInstall(webstore_install::INVALID_WEBSTORE_RESPONSE, error);
[email protected]8915f342011-08-29 22:14:37287}
288
[email protected]734bcec2012-10-08 20:29:05289void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
[email protected]98e4e522011-10-25 13:00:16290 const std::string& id,
[email protected]8915f342011-08-29 22:14:37291 const SkBitmap& icon,
292 base::DictionaryValue* manifest) {
[email protected]d44ec7b2013-03-15 04:34:34293 CHECK_EQ(id_, id);
294
295 if (!CheckRequestorAlive()) {
[email protected]9c7b3092014-06-21 01:19:03296 CompleteInstall(webstore_install::ABORTED, std::string());
[email protected]2fd920fb2011-09-08 23:33:00297 return;
298 }
299
[email protected]8915f342011-08-29 22:14:37300 manifest_.reset(manifest);
301 icon_ = icon;
302
[email protected]9c7b3092014-06-21 01:19:03303 OnManifestParsed();
[email protected]8915f342011-08-29 22:14:37304}
305
[email protected]734bcec2012-10-08 20:29:05306void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
[email protected]98e4e522011-10-25 13:00:16307 const std::string& id,
[email protected]8915f342011-08-29 22:14:37308 InstallHelperResultCode result_code,
309 const std::string& error_message) {
[email protected]ced522c2014-07-23 20:23:59310 webstore_install::Result install_result = webstore_install::OTHER_ERROR;
[email protected]9c7b3092014-06-21 01:19:03311 switch (result_code) {
312 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR:
313 install_result = webstore_install::INVALID_MANIFEST;
314 break;
315 case WebstoreInstallHelper::Delegate::ICON_ERROR:
316 install_result = webstore_install::ICON_ERROR;
317 break;
318 default:
319 break;
320 }
321
322 CompleteInstall(install_result, error_message);
[email protected]8915f342011-08-29 22:14:37323}
324
[email protected]734bcec2012-10-08 20:29:05325void WebstoreStandaloneInstaller::InstallUIProceed() {
[email protected]d44ec7b2013-03-15 04:34:34326 if (!CheckRequestorAlive()) {
[email protected]9c7b3092014-06-21 01:19:03327 CompleteInstall(webstore_install::ABORTED, std::string());
[email protected]2fd920fb2011-09-08 23:33:00328 return;
329 }
330
[email protected]760f743b2014-05-28 13:52:02331 scoped_ptr<WebstoreInstaller::Approval> approval = CreateApproval();
332
[email protected]f6b88d92014-01-09 19:45:34333 ExtensionService* extension_service =
334 ExtensionSystem::Get(profile_)->extension_service();
[email protected]9c7b3092014-06-21 01:19:03335 const Extension* installed_extension =
[email protected]f6b88d92014-01-09 19:45:34336 extension_service->GetExtensionById(id_, true /* include disabled */);
[email protected]9c7b3092014-06-21 01:19:03337 if (installed_extension) {
338 std::string install_message;
339 webstore_install::Result install_result = webstore_install::SUCCESS;
340 bool done = true;
[email protected]ba9ca762014-02-24 02:12:40341
[email protected]760f743b2014-05-28 13:52:02342 if (ExtensionPrefs::Get(profile_)->IsExtensionBlacklisted(id_)) {
343 // Don't install a blacklisted extension.
[email protected]9c7b3092014-06-21 01:19:03344 install_result = webstore_install::BLACKLISTED;
345 install_message = kExtensionIsBlacklisted;
346 } else if (util::IsEphemeralApp(installed_extension->id(), profile_) &&
[email protected]760f743b2014-05-28 13:52:02347 !approval->is_ephemeral) {
[email protected]9c7b3092014-06-21 01:19:03348 // If the target extension has already been installed ephemerally and is
349 // up to date, it can be promoted to a regular installed extension and
350 // downloading from the Web Store is not necessary.
351 const Extension* extension_to_install = GetLocalizedExtensionForDisplay();
352 if (!extension_to_install) {
353 CompleteInstall(webstore_install::INVALID_MANIFEST,
354 kInvalidManifestError);
355 return;
356 }
357
358 if (installed_extension->version()->CompareTo(
359 *extension_to_install->version()) < 0) {
360 // If the existing extension is out of date, proceed with the install
361 // to update the extension.
362 done = false;
363 } else {
[email protected]453ac122014-07-28 03:32:13364 install_ui::ShowPostInstallUIForApproval(
365 profile_, *approval, installed_extension);
[email protected]9c7b3092014-06-21 01:19:03366 extension_service->PromoteEphemeralApp(installed_extension, false);
367 }
[email protected]760f743b2014-05-28 13:52:02368 } else if (!extension_service->IsExtensionEnabled(id_)) {
369 // If the extension is installed but disabled, and not blacklisted,
370 // enable it.
371 extension_service->EnableExtension(id_);
372 } // else extension is installed and enabled; no work to be done.
373
[email protected]9c7b3092014-06-21 01:19:03374 if (done) {
375 CompleteInstall(install_result, install_message);
376 return;
377 }
[email protected]f6b88d92014-01-09 19:45:34378 }
379
[email protected]98e4e522011-10-25 13:00:16380 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
[email protected]d44ec7b2013-03-15 04:34:34381 profile_,
382 this,
[email protected]2acf3a52014-02-13 00:26:00383 GetWebContents(),
[email protected]d44ec7b2013-03-15 04:34:34384 id_,
385 approval.Pass(),
[email protected]084e35482013-09-25 02:46:19386 install_source_);
[email protected]98e4e522011-10-25 13:00:16387 installer->Start();
[email protected]8915f342011-08-29 22:14:37388}
389
[email protected]734bcec2012-10-08 20:29:05390void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
[email protected]9c7b3092014-06-21 01:19:03391 CompleteInstall(webstore_install::USER_CANCELLED, kUserCancelledError);
[email protected]8915f342011-08-29 22:14:37392}
393
[email protected]734bcec2012-10-08 20:29:05394void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
395 const std::string& id) {
[email protected]cb08ba22011-10-19 21:41:40396 CHECK_EQ(id_, id);
[email protected]9c7b3092014-06-21 01:19:03397 CompleteInstall(webstore_install::SUCCESS, std::string());
[email protected]cb08ba22011-10-19 21:41:40398}
399
[email protected]734bcec2012-10-08 20:29:05400void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
[email protected]bcd1eaf72012-10-03 05:42:29401 const std::string& id,
402 const std::string& error,
[email protected]9c7b3092014-06-21 01:19:03403 WebstoreInstaller::FailureReason reason) {
[email protected]cb08ba22011-10-19 21:41:40404 CHECK_EQ(id_, id);
[email protected]cb08ba22011-10-19 21:41:40405
[email protected]ced522c2014-07-23 20:23:59406 webstore_install::Result install_result = webstore_install::OTHER_ERROR;
[email protected]9c7b3092014-06-21 01:19:03407 switch (reason) {
408 case WebstoreInstaller::FAILURE_REASON_CANCELLED:
409 install_result = webstore_install::USER_CANCELLED;
410 break;
411 case WebstoreInstaller::FAILURE_REASON_DEPENDENCY_NOT_FOUND:
412 case WebstoreInstaller::FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE:
413 install_result = webstore_install::MISSING_DEPENDENCIES;
414 break;
415 default:
416 break;
[email protected]d44ec7b2013-03-15 04:34:34417 }
[email protected]d44ec7b2013-03-15 04:34:34418
[email protected]9c7b3092014-06-21 01:19:03419 CompleteInstall(install_result, error);
[email protected]8915f342011-08-29 22:14:37420}
[email protected]5f2a4752012-04-27 22:18:58421
[email protected]e263a6b62014-06-05 23:19:49422void WebstoreStandaloneInstaller::ShowInstallUI() {
[email protected]9c7b3092014-06-21 01:19:03423 const Extension* localized_extension = GetLocalizedExtensionForDisplay();
424 if (!localized_extension) {
425 CompleteInstall(webstore_install::INVALID_MANIFEST, kInvalidManifestError);
[email protected]d44ec7b2013-03-15 04:34:34426 return;
[email protected]5f2a4752012-04-27 22:18:58427 }
[email protected]5f2a4752012-04-27 22:18:58428
[email protected]f8b23b42013-06-27 20:12:14429 install_ui_ = CreateInstallUI();
[email protected]dc24976f2013-06-02 21:15:09430 install_ui_->ConfirmStandaloneInstall(
[email protected]9c7b3092014-06-21 01:19:03431 this, localized_extension, &icon_, install_prompt_);
[email protected]5f2a4752012-04-27 22:18:58432}
[email protected]3d61a7f2012-07-12 19:11:25433
[email protected]e263a6b62014-06-05 23:19:49434void WebstoreStandaloneInstaller::OnWebStoreDataFetcherDone() {
435 // An instance of this class is passed in as a delegate for the
436 // WebstoreInstallHelper, ExtensionInstallPrompt and WebstoreInstaller, and
437 // therefore needs to remain alive until they are done. Clear the webstore
438 // data fetcher to avoid calling Release in AbortInstall while any of these
439 // operations are in progress.
440 webstore_data_fetcher_.reset();
441}
442
[email protected]3d61a7f2012-07-12 19:11:25443} // namespace extensions