EME test page application.
[chromium-blink-merge.git] / chrome / browser / extensions / webstore_standalone_installer.cc
blob91662ea6750c4fd732d894f2b803da64b3c321f8
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_registry.h"
17 #include "extensions/browser/extension_system.h"
18 #include "extensions/browser/extension_util.h"
19 #include "extensions/common/extension.h"
20 #include "url/gurl.h"
22 using content::WebContents;
24 namespace extensions {
26 const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
27 const char kWebstoreRequestError[] =
28 "Could not fetch data from the Chrome Web Store";
29 const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
30 const char kInvalidManifestError[] = "Invalid manifest";
31 const char kUserCancelledError[] = "User cancelled install";
32 const char kExtensionIsBlacklisted[] = "Extension is blacklisted";
34 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
35 const std::string& webstore_item_id,
36 Profile* profile,
37 const Callback& callback)
38 : id_(webstore_item_id),
39 callback_(callback),
40 profile_(profile),
41 install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE),
42 show_user_count_(true),
43 average_rating_(0.0),
44 rating_count_(0) {
47 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
50 // Private interface implementation.
53 void WebstoreStandaloneInstaller::BeginInstall() {
54 // Add a ref to keep this alive for WebstoreDataFetcher.
55 // All code paths from here eventually lead to either CompleteInstall or
56 // AbortInstall, which both release this ref.
57 AddRef();
59 if (!Extension::IdIsValid(id_)) {
60 CompleteInstall(kInvalidWebstoreItemId);
61 return;
64 // Use the requesting page as the referrer both since that is more correct
65 // (it is the page that caused this request to happen) and so that we can
66 // track top sites that trigger inline install requests.
67 webstore_data_fetcher_.reset(new WebstoreDataFetcher(
68 this,
69 profile_->GetRequestContext(),
70 GetRequestorURL(),
71 id_));
72 webstore_data_fetcher_->Start();
75 bool WebstoreStandaloneInstaller::CheckInstallValid(
76 const base::DictionaryValue& manifest,
77 std::string* error) {
78 return true;
81 scoped_ptr<ExtensionInstallPrompt>
82 WebstoreStandaloneInstaller::CreateInstallUI() {
83 return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
86 scoped_ptr<WebstoreInstaller::Approval>
87 WebstoreStandaloneInstaller::CreateApproval() const {
88 scoped_ptr<WebstoreInstaller::Approval> approval(
89 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
90 profile_,
91 id_,
92 scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy()),
93 true));
94 approval->skip_post_install_ui = !ShouldShowPostInstallUI();
95 approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
96 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
97 return approval.Pass();
100 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
101 CompleteInstall(kWebstoreRequestError);
104 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
105 scoped_ptr<base::DictionaryValue> webstore_data) {
106 if (!CheckRequestorAlive()) {
107 CompleteInstall(std::string());
108 return;
111 std::string error;
113 if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
114 CompleteInstall(error);
115 return;
118 if (!CheckRequestorPermitted(*webstore_data, &error)) {
119 CompleteInstall(error);
120 return;
123 // Manifest, number of users, average rating and rating count are required.
124 std::string manifest;
125 if (!webstore_data->GetString(kManifestKey, &manifest) ||
126 !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
127 !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
128 !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
129 CompleteInstall(kInvalidWebstoreResponseError);
130 return;
133 // Optional.
134 show_user_count_ = true;
135 webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);
137 if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
138 average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
139 CompleteInstall(kInvalidWebstoreResponseError);
140 return;
143 // Localized name and description are optional.
144 if ((webstore_data->HasKey(kLocalizedNameKey) &&
145 !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
146 (webstore_data->HasKey(kLocalizedDescriptionKey) &&
147 !webstore_data->GetString(
148 kLocalizedDescriptionKey, &localized_description_))) {
149 CompleteInstall(kInvalidWebstoreResponseError);
150 return;
153 // Icon URL is optional.
154 GURL icon_url;
155 if (webstore_data->HasKey(kIconUrlKey)) {
156 std::string icon_url_string;
157 if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
158 CompleteInstall(kInvalidWebstoreResponseError);
159 return;
161 icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
162 icon_url_string);
163 if (!icon_url.is_valid()) {
164 CompleteInstall(kInvalidWebstoreResponseError);
165 return;
169 // Assume ownership of webstore_data.
170 webstore_data_ = webstore_data.Pass();
172 scoped_refptr<WebstoreInstallHelper> helper =
173 new WebstoreInstallHelper(this,
174 id_,
175 manifest,
176 std::string(), // We don't have any icon data.
177 icon_url,
178 profile_->GetRequestContext());
179 // The helper will call us back via OnWebstoreParseSucces or
180 // OnWebstoreParseFailure.
181 helper->Start();
184 void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
185 const std::string& error) {
186 CompleteInstall(error);
189 void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
190 const std::string& id,
191 const SkBitmap& icon,
192 base::DictionaryValue* manifest) {
193 CHECK_EQ(id_, id);
195 if (!CheckRequestorAlive()) {
196 CompleteInstall(std::string());
197 return;
200 manifest_.reset(manifest);
201 icon_ = icon;
203 std::string error;
204 if (!CheckInstallValid(*manifest, &error)) {
205 DCHECK(!error.empty());
206 CompleteInstall(error);
207 return;
210 install_prompt_ = CreateInstallPrompt();
211 if (install_prompt_) {
212 ShowInstallUI();
213 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
214 } else {
215 // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
216 // OnExtensionInstallSuccess or OnExtensionInstallFailure.
217 AddRef();
218 InstallUIProceed();
222 void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
223 const std::string& id,
224 InstallHelperResultCode result_code,
225 const std::string& error_message) {
226 CompleteInstall(error_message);
229 void WebstoreStandaloneInstaller::InstallUIProceed() {
230 if (!CheckRequestorAlive()) {
231 CompleteInstall(std::string());
232 return;
235 scoped_ptr<WebstoreInstaller::Approval> approval = CreateApproval();
237 ExtensionService* extension_service =
238 ExtensionSystem::Get(profile_)->extension_service();
239 const Extension* extension =
240 extension_service->GetExtensionById(id_, true /* include disabled */);
241 if (extension) {
242 std::string install_result; // Empty string for install success.
244 if (ExtensionPrefs::Get(profile_)->IsExtensionBlacklisted(id_)) {
245 // Don't install a blacklisted extension.
246 install_result = kExtensionIsBlacklisted;
247 } else if (util::IsEphemeralApp(extension->id(), profile_) &&
248 !approval->is_ephemeral) {
249 // If the target extension has already been installed ephemerally, it can
250 // be promoted to a regular installed extension and downloading from the
251 // Web Store is not necessary.
252 extension_service->PromoteEphemeralApp(extension, false);
253 } else if (!extension_service->IsExtensionEnabled(id_)) {
254 // If the extension is installed but disabled, and not blacklisted,
255 // enable it.
256 extension_service->EnableExtension(id_);
257 } // else extension is installed and enabled; no work to be done.
259 CompleteInstall(install_result);
260 return;
263 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
264 profile_,
265 this,
266 GetWebContents(),
267 id_,
268 approval.Pass(),
269 install_source_);
270 installer->Start();
273 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
274 CompleteInstall(kUserCancelledError);
275 Release(); // Balanced in ShowInstallUI.
278 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
279 const std::string& id) {
280 CHECK_EQ(id_, id);
281 CompleteInstall(std::string());
282 Release(); // Balanced in ShowInstallUI.
285 void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
286 const std::string& id,
287 const std::string& error,
288 WebstoreInstaller::FailureReason cancelled) {
289 CHECK_EQ(id_, id);
290 CompleteInstall(error);
291 Release(); // Balanced in ShowInstallUI.
294 void WebstoreStandaloneInstaller::AbortInstall() {
295 callback_.Reset();
296 // Abort any in-progress fetches.
297 if (webstore_data_fetcher_) {
298 webstore_data_fetcher_.reset();
299 Release(); // Matches the AddRef in BeginInstall.
303 void WebstoreStandaloneInstaller::InvokeCallback(const std::string& error) {
304 if (!callback_.is_null())
305 callback_.Run(error.empty(), error);
308 void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
309 InvokeCallback(error);
310 Release(); // Matches the AddRef in BeginInstall.
313 void
314 WebstoreStandaloneInstaller::ShowInstallUI() {
315 std::string error;
316 localized_extension_for_display_ =
317 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
318 manifest_.get(),
319 Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
320 id_,
321 localized_name_,
322 localized_description_,
323 &error);
324 if (!localized_extension_for_display_.get()) {
325 CompleteInstall(kInvalidManifestError);
326 return;
329 // Keep this alive as long as the install prompt lives.
330 // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
331 // OnExtensionInstallSuccess or OnExtensionInstallFailure.
332 AddRef();
334 install_ui_ = CreateInstallUI();
335 install_ui_->ConfirmStandaloneInstall(
336 this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
339 } // namespace extensions