webstore_standalone_installer.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/webstore_standalone_installer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/crx_installer.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_install_prompt.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_install_ui.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_data_fetcher.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kWebstoreRequestError[] =
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Could not fetch data from the Chrome Web Store";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidManifestError[] = "Invalid manifest";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUserCancelledError[] = "User cancelled install";
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kExtensionIsBlacklisted[] = "Extension is blacklisted";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& webstore_item_id,
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile,
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Callback& callback)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : id_(webstore_item_id),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_(callback),
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_(profile),
3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE),
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      show_user_count_(true),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      average_rating_(0.0),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rating_count_(0) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Private interface implementation.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::BeginInstall() {
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Add a ref to keep this alive for WebstoreDataFetcher.
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // All code paths from here eventually lead to either CompleteInstall or
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // AbortInstall, which both release this ref.
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddRef();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Extension::IdIsValid(id_)) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteInstall(kInvalidWebstoreItemId);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use the requesting page as the referrer both since that is more correct
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (it is the page that caused this request to happen) and so that we can
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // track top sites that trigger inline install requests.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_data_fetcher_.reset(new WebstoreDataFetcher(
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this,
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_->GetRequestContext(),
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetRequestorURL(),
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id_));
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_data_fetcher_->Start();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool WebstoreStandaloneInstaller::CheckInstallValid(
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::DictionaryValue& manifest,
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string* error) {
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<ExtensionInstallPrompt>
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWebstoreStandaloneInstaller::CreateInstallUI() {
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_ptr<WebstoreInstaller::Approval>
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)WebstoreStandaloneInstaller::CreateApproval() const {
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<WebstoreInstaller::Approval> approval(
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          profile_,
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          id_,
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy()),
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          true));
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  approval->skip_post_install_ui = !ShouldShowPostInstallUI();
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return approval.Pass();
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CompleteInstall(kWebstoreRequestError);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> webstore_data) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CheckRequestorAlive()) {
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CompleteInstall(std::string());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string error;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CompleteInstall(error);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CheckRequestorPermitted(*webstore_data, &error)) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CompleteInstall(error);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Manifest, number of users, average rating and rating count are required.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string manifest;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!webstore_data->GetString(kManifestKey, &manifest) ||
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteInstall(kInvalidWebstoreResponseError);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Optional.
132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  show_user_count_ = true;
133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);
134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteInstall(kInvalidWebstoreResponseError);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Localized name and description are optional.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((webstore_data->HasKey(kLocalizedNameKey) &&
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (webstore_data->HasKey(kLocalizedDescriptionKey) &&
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !webstore_data->GetString(
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kLocalizedDescriptionKey, &localized_description_))) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteInstall(kInvalidWebstoreResponseError);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Icon URL is optional.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL icon_url;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (webstore_data->HasKey(kIconUrlKey)) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string icon_url_string;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CompleteInstall(kInvalidWebstoreResponseError);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon_url_string);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!icon_url.is_valid()) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CompleteInstall(kInvalidWebstoreResponseError);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Assume ownership of webstore_data.
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  webstore_data_ = webstore_data.Pass();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_refptr<WebstoreInstallHelper> helper =
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new WebstoreInstallHelper(this,
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                id_,
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                manifest,
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                std::string(),  // We don't have any icon data.
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                icon_url,
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                profile_->GetRequestContext());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The helper will call us back via OnWebstoreParseSucces or
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OnWebstoreParseFailure.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  helper->Start();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& error) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteInstall(error);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SkBitmap& icon,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue* manifest) {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_EQ(id_, id);
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CheckRequestorAlive()) {
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CompleteInstall(std::string());
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manifest_.reset(manifest);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_ = icon;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string error;
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckInstallValid(*manifest, &error)) {
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(!error.empty());
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    CompleteInstall(error);
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  install_prompt_ = CreateInstallPrompt();
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (install_prompt_) {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ShowInstallUI();
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Control flow finishes up in InstallUIProceed or InstallUIAbort.
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // OnExtensionInstallSuccess or OnExtensionInstallFailure.
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    AddRef();
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InstallUIProceed();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InstallHelperResultCode result_code,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& error_message) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteInstall(error_message);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::InstallUIProceed() {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CheckRequestorAlive()) {
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CompleteInstall(std::string());
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionService* extension_service =
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionSystem::Get(profile_)->extension_service();
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Extension* extension =
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extension_service->GetExtensionById(id_, true /* include disabled */);
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (extension) {
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string install_result;  // Empty string for install success.
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!extension_service->IsExtensionEnabled(id_)) {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!ExtensionPrefs::Get(profile_)->IsExtensionBlacklisted(id_)) {
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // If the extension is installed but disabled, and not blacklisted,
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // enable it.
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extension_service->EnableExtension(id_);
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {  // Don't install a blacklisted extension.
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        install_result = kExtensionIsBlacklisted;
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }  // else extension is installed and enabled; no work to be done.
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CompleteInstall(install_result);
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<WebstoreInstaller::Approval> approval = CreateApproval();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_,
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this,
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetWebContents(),
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id_,
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      approval.Pass(),
26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      install_source_);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  installer->Start();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteInstall(kUserCancelledError);
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Release();  // Balanced in ShowInstallUI.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(id_, id);
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteInstall(std::string());
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Release();  // Balanced in ShowInstallUI.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& error,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebstoreInstaller::FailureReason cancelled) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(id_, id);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteInstall(error);
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Release();  // Balanced in ShowInstallUI.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebstoreStandaloneInstaller::AbortInstall() {
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_.Reset();
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Abort any in-progress fetches.
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (webstore_data_fetcher_) {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    webstore_data_fetcher_.reset();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Release();  // Matches the AddRef in BeginInstall.
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebstoreStandaloneInstaller::InvokeCallback(const std::string& error) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null())
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Run(error.empty(), error);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InvokeCallback(error);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Release();  // Matches the AddRef in BeginInstall.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWebstoreStandaloneInstaller::ShowInstallUI() {
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string error;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  localized_extension_for_display_ =
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          manifest_.get(),
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          id_,
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          localized_name_,
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          localized_description_,
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &error);
315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!localized_extension_for_display_.get()) {
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CompleteInstall(kInvalidManifestError);
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Keep this alive as long as the install prompt lives.
3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // OnExtensionInstallSuccess or OnExtensionInstallFailure.
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddRef();
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  install_ui_ = CreateInstallUI();
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  install_ui_->ConfirmStandaloneInstall(
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
331