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.
5 #include "chrome/browser/extensions/webstore_standalone_installer.h"
7 #include "base/values.h"
8 #include "chrome/browser/extensions/crx_installer.h"
9 #include "chrome/browser/extensions/extension_install_prompt.h"
10 #include "chrome/browser/extensions/extension_install_ui.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/webstore_data_fetcher.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "content/public/browser/web_contents.h"
15 #include "extensions/browser/extension_prefs.h"
16 #include "extensions/browser/extension_system.h"
17 #include "extensions/common/extension.h"
20 using content::WebContents
;
22 namespace extensions
{
24 const char kInvalidWebstoreItemId
[] = "Invalid Chrome Web Store item ID";
25 const char kWebstoreRequestError
[] =
26 "Could not fetch data from the Chrome Web Store";
27 const char kInvalidWebstoreResponseError
[] = "Invalid Chrome Web Store reponse";
28 const char kInvalidManifestError
[] = "Invalid manifest";
29 const char kUserCancelledError
[] = "User cancelled install";
30 const char kExtensionIsBlacklisted
[] = "Extension is blacklisted";
32 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
33 const std::string
& webstore_item_id
,
35 const Callback
& callback
)
36 : id_(webstore_item_id
),
39 install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE
),
40 show_user_count_(true),
45 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
48 // Private interface implementation.
51 void WebstoreStandaloneInstaller::BeginInstall() {
52 // Add a ref to keep this alive for WebstoreDataFetcher.
53 // All code paths from here eventually lead to either CompleteInstall or
54 // AbortInstall, which both release this ref.
57 if (!Extension::IdIsValid(id_
)) {
58 CompleteInstall(kInvalidWebstoreItemId
);
62 // Use the requesting page as the referrer both since that is more correct
63 // (it is the page that caused this request to happen) and so that we can
64 // track top sites that trigger inline install requests.
65 webstore_data_fetcher_
.reset(new WebstoreDataFetcher(
67 profile_
->GetRequestContext(),
70 webstore_data_fetcher_
->Start();
73 bool WebstoreStandaloneInstaller::CheckInstallValid(
74 const base::DictionaryValue
& manifest
,
79 scoped_ptr
<ExtensionInstallPrompt
>
80 WebstoreStandaloneInstaller::CreateInstallUI() {
81 return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
84 scoped_ptr
<WebstoreInstaller::Approval
>
85 WebstoreStandaloneInstaller::CreateApproval() const {
86 scoped_ptr
<WebstoreInstaller::Approval
> approval(
87 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
90 scoped_ptr
<base::DictionaryValue
>(manifest_
.get()->DeepCopy()),
92 approval
->skip_post_install_ui
= !ShouldShowPostInstallUI();
93 approval
->use_app_installed_bubble
= ShouldShowAppInstalledBubble();
94 approval
->installing_icon
= gfx::ImageSkia::CreateFrom1xBitmap(icon_
);
95 return approval
.Pass();
98 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
99 CompleteInstall(kWebstoreRequestError
);
102 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
103 scoped_ptr
<base::DictionaryValue
> webstore_data
) {
104 if (!CheckRequestorAlive()) {
105 CompleteInstall(std::string());
111 if (!CheckInlineInstallPermitted(*webstore_data
, &error
)) {
112 CompleteInstall(error
);
116 if (!CheckRequestorPermitted(*webstore_data
, &error
)) {
117 CompleteInstall(error
);
121 // Manifest, number of users, average rating and rating count are required.
122 std::string manifest
;
123 if (!webstore_data
->GetString(kManifestKey
, &manifest
) ||
124 !webstore_data
->GetString(kUsersKey
, &localized_user_count_
) ||
125 !webstore_data
->GetDouble(kAverageRatingKey
, &average_rating_
) ||
126 !webstore_data
->GetInteger(kRatingCountKey
, &rating_count_
)) {
127 CompleteInstall(kInvalidWebstoreResponseError
);
132 show_user_count_
= true;
133 webstore_data
->GetBoolean(kShowUserCountKey
, &show_user_count_
);
135 if (average_rating_
< ExtensionInstallPrompt::kMinExtensionRating
||
136 average_rating_
> ExtensionInstallPrompt::kMaxExtensionRating
) {
137 CompleteInstall(kInvalidWebstoreResponseError
);
141 // Localized name and description are optional.
142 if ((webstore_data
->HasKey(kLocalizedNameKey
) &&
143 !webstore_data
->GetString(kLocalizedNameKey
, &localized_name_
)) ||
144 (webstore_data
->HasKey(kLocalizedDescriptionKey
) &&
145 !webstore_data
->GetString(
146 kLocalizedDescriptionKey
, &localized_description_
))) {
147 CompleteInstall(kInvalidWebstoreResponseError
);
151 // Icon URL is optional.
153 if (webstore_data
->HasKey(kIconUrlKey
)) {
154 std::string icon_url_string
;
155 if (!webstore_data
->GetString(kIconUrlKey
, &icon_url_string
)) {
156 CompleteInstall(kInvalidWebstoreResponseError
);
159 icon_url
= GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
161 if (!icon_url
.is_valid()) {
162 CompleteInstall(kInvalidWebstoreResponseError
);
167 // Assume ownership of webstore_data.
168 webstore_data_
= webstore_data
.Pass();
170 scoped_refptr
<WebstoreInstallHelper
> helper
=
171 new WebstoreInstallHelper(this,
174 std::string(), // We don't have any icon data.
176 profile_
->GetRequestContext());
177 // The helper will call us back via OnWebstoreParseSucces or
178 // OnWebstoreParseFailure.
182 void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
183 const std::string
& error
) {
184 CompleteInstall(error
);
187 void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
188 const std::string
& id
,
189 const SkBitmap
& icon
,
190 base::DictionaryValue
* manifest
) {
193 if (!CheckRequestorAlive()) {
194 CompleteInstall(std::string());
198 manifest_
.reset(manifest
);
202 if (!CheckInstallValid(*manifest
, &error
)) {
203 DCHECK(!error
.empty());
204 CompleteInstall(error
);
208 install_prompt_
= CreateInstallPrompt();
209 if (install_prompt_
) {
211 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
213 // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
214 // OnExtensionInstallSuccess or OnExtensionInstallFailure.
220 void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
221 const std::string
& id
,
222 InstallHelperResultCode result_code
,
223 const std::string
& error_message
) {
224 CompleteInstall(error_message
);
227 void WebstoreStandaloneInstaller::InstallUIProceed() {
228 if (!CheckRequestorAlive()) {
229 CompleteInstall(std::string());
233 ExtensionService
* extension_service
=
234 ExtensionSystem::Get(profile_
)->extension_service();
235 const Extension
* extension
=
236 extension_service
->GetExtensionById(id_
, true /* include disabled */);
238 std::string install_result
; // Empty string for install success.
239 if (!extension_service
->IsExtensionEnabled(id_
)) {
240 if (!ExtensionPrefs::Get(profile_
)->IsExtensionBlacklisted(id_
)) {
241 // If the extension is installed but disabled, and not blacklisted,
243 extension_service
->EnableExtension(id_
);
244 } else { // Don't install a blacklisted extension.
245 install_result
= kExtensionIsBlacklisted
;
247 } // else extension is installed and enabled; no work to be done.
248 CompleteInstall(install_result
);
252 scoped_ptr
<WebstoreInstaller::Approval
> approval
= CreateApproval();
254 scoped_refptr
<WebstoreInstaller
> installer
= new WebstoreInstaller(
264 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated
) {
265 CompleteInstall(kUserCancelledError
);
266 Release(); // Balanced in ShowInstallUI.
269 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
270 const std::string
& id
) {
272 CompleteInstall(std::string());
273 Release(); // Balanced in ShowInstallUI.
276 void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
277 const std::string
& id
,
278 const std::string
& error
,
279 WebstoreInstaller::FailureReason cancelled
) {
281 CompleteInstall(error
);
282 Release(); // Balanced in ShowInstallUI.
285 void WebstoreStandaloneInstaller::AbortInstall() {
287 // Abort any in-progress fetches.
288 if (webstore_data_fetcher_
) {
289 webstore_data_fetcher_
.reset();
290 Release(); // Matches the AddRef in BeginInstall.
294 void WebstoreStandaloneInstaller::InvokeCallback(const std::string
& error
) {
295 if (!callback_
.is_null())
296 callback_
.Run(error
.empty(), error
);
299 void WebstoreStandaloneInstaller::CompleteInstall(const std::string
& error
) {
300 InvokeCallback(error
);
301 Release(); // Matches the AddRef in BeginInstall.
305 WebstoreStandaloneInstaller::ShowInstallUI() {
307 localized_extension_for_display_
=
308 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
310 Extension::REQUIRE_KEY
| Extension::FROM_WEBSTORE
,
313 localized_description_
,
315 if (!localized_extension_for_display_
.get()) {
316 CompleteInstall(kInvalidManifestError
);
320 // Keep this alive as long as the install prompt lives.
321 // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
322 // OnExtensionInstallSuccess or OnExtensionInstallFailure.
325 install_ui_
= CreateInstallUI();
326 install_ui_
->ConfirmStandaloneInstall(
327 this, localized_extension_for_display_
.get(), &icon_
, *install_prompt_
);
330 } // namespace extensions