- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / webstore_standalone_installer.cc
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/webstore_standalone_installer.h"
6
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 "chrome/common/extensions/extension.h"
15 #include "content/public/browser/web_contents.h"
16 #include "url/gurl.h"
17
18 using content::WebContents;
19
20 namespace extensions {
21
22 const char kManifestKey[] = "manifest";
23 const char kIconUrlKey[] = "icon_url";
24 const char kLocalizedNameKey[] = "localized_name";
25 const char kLocalizedDescriptionKey[] = "localized_description";
26 const char kUsersKey[] = "users";
27 const char kShowUserCountKey[] = "show_user_count";
28 const char kAverageRatingKey[] = "average_rating";
29 const char kRatingCountKey[] = "rating_count";
30
31 const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
32 const char kWebstoreRequestError[] =
33     "Could not fetch data from the Chrome Web Store";
34 const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
35 const char kInvalidManifestError[] = "Invalid manifest";
36 const char kUserCancelledError[] = "User cancelled install";
37
38
39 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
40     const std::string& webstore_item_id,
41     Profile* profile,
42     const Callback& callback)
43     : id_(webstore_item_id),
44       callback_(callback),
45       profile_(profile),
46       install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE),
47       show_user_count_(true),
48       average_rating_(0.0),
49       rating_count_(0) {
50   CHECK(!callback_.is_null());
51 }
52
53 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
54
55 //
56 // Private interface implementation.
57 //
58
59 void WebstoreStandaloneInstaller::BeginInstall() {
60   // Add a ref to keep this alive for WebstoreDataFetcher.
61   // All code paths from here eventually lead to either CompleteInstall or
62   // AbortInstall, which both release this ref.
63   AddRef();
64
65   if (!Extension::IdIsValid(id_)) {
66     CompleteInstall(kInvalidWebstoreItemId);
67     return;
68   }
69
70   // 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.
73   webstore_data_fetcher_.reset(new WebstoreDataFetcher(
74       this,
75       profile_->GetRequestContext(),
76       GetRequestorURL(),
77       id_));
78   webstore_data_fetcher_->Start();
79 }
80
81 scoped_ptr<ExtensionInstallPrompt>
82 WebstoreStandaloneInstaller::CreateInstallUI() {
83   return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
84 }
85
86 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
87   CompleteInstall(kWebstoreRequestError);
88 }
89
90 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
91     DictionaryValue* webstore_data) {
92   if (!CheckRequestorAlive()) {
93     CompleteInstall(std::string());
94     return;
95   }
96
97   std::string error;
98
99   if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
100     CompleteInstall(error);
101     return;
102   }
103
104   if (!CheckRequestorPermitted(*webstore_data, &error)) {
105     CompleteInstall(error);
106     return;
107   }
108
109   // Manifest, number of users, average rating and rating count are required.
110   std::string manifest;
111   if (!webstore_data->GetString(kManifestKey, &manifest) ||
112       !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
113       !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
114       !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
115     CompleteInstall(kInvalidWebstoreResponseError);
116     return;
117   }
118
119   // Optional.
120   show_user_count_ = true;
121   webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);
122
123   if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
124       average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
125     CompleteInstall(kInvalidWebstoreResponseError);
126     return;
127   }
128
129   // Localized name and description are optional.
130   if ((webstore_data->HasKey(kLocalizedNameKey) &&
131       !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
132       (webstore_data->HasKey(kLocalizedDescriptionKey) &&
133       !webstore_data->GetString(
134           kLocalizedDescriptionKey, &localized_description_))) {
135     CompleteInstall(kInvalidWebstoreResponseError);
136     return;
137   }
138
139   // Icon URL is optional.
140   GURL icon_url;
141   if (webstore_data->HasKey(kIconUrlKey)) {
142     std::string icon_url_string;
143     if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
144       CompleteInstall(kInvalidWebstoreResponseError);
145       return;
146     }
147     icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
148         icon_url_string);
149     if (!icon_url.is_valid()) {
150       CompleteInstall(kInvalidWebstoreResponseError);
151       return;
152     }
153   }
154
155   // Assume ownership of webstore_data.
156   webstore_data_.reset(webstore_data);
157
158   scoped_refptr<WebstoreInstallHelper> helper =
159       new WebstoreInstallHelper(this,
160                                 id_,
161                                 manifest,
162                                 std::string(),  // We don't have any icon data.
163                                 icon_url,
164                                 profile_->GetRequestContext());
165   // The helper will call us back via OnWebstoreParseSucces or
166   // OnWebstoreParseFailure.
167   helper->Start();
168 }
169
170 void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
171     const std::string& error) {
172   CompleteInstall(error);
173 }
174
175 void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
176     const std::string& id,
177     const SkBitmap& icon,
178     base::DictionaryValue* manifest) {
179   CHECK_EQ(id_, id);
180
181   if (!CheckRequestorAlive()) {
182     CompleteInstall(std::string());
183     return;
184   }
185
186   manifest_.reset(manifest);
187   icon_ = icon;
188
189   install_prompt_ = CreateInstallPrompt();
190   if (install_prompt_) {
191     ShowInstallUI();
192     // Control flow finishes up in InstallUIProceed or InstallUIAbort.
193   } else {
194     // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
195     // OnExtensionInstallSuccess or OnExtensionInstallFailure.
196     AddRef();
197     InstallUIProceed();
198   }
199 }
200
201 void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
202     const std::string& id,
203     InstallHelperResultCode result_code,
204     const std::string& error_message) {
205   CompleteInstall(error_message);
206 }
207
208 void WebstoreStandaloneInstaller::InstallUIProceed() {
209   if (!CheckRequestorAlive()) {
210     CompleteInstall(std::string());
211     return;
212   }
213
214   scoped_ptr<WebstoreInstaller::Approval> approval(
215       WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
216           profile_,
217           id_,
218           scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy()),
219           true));
220   approval->skip_post_install_ui = !ShouldShowPostInstallUI();
221   approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
222   approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
223
224   scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
225       profile_,
226       this,
227       &(GetWebContents()->GetController()),
228       id_,
229       approval.Pass(),
230       install_source_);
231   installer->Start();
232 }
233
234 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
235   CompleteInstall(kUserCancelledError);
236   Release();  // Balanced in ShowInstallUI.
237 }
238
239 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
240     const std::string& id) {
241   CHECK_EQ(id_, id);
242   CompleteInstall(std::string());
243   Release();  // Balanced in ShowInstallUI.
244 }
245
246 void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
247     const std::string& id,
248     const std::string& error,
249     WebstoreInstaller::FailureReason cancelled) {
250   CHECK_EQ(id_, id);
251   CompleteInstall(error);
252   Release();  // Balanced in ShowInstallUI.
253 }
254
255 void WebstoreStandaloneInstaller::AbortInstall() {
256   callback_.Reset();
257   // Abort any in-progress fetches.
258   if (webstore_data_fetcher_) {
259     webstore_data_fetcher_.reset();
260     Release();  // Matches the AddRef in BeginInstall.
261   }
262 }
263
264 void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
265   if (!callback_.is_null())
266     callback_.Run(error.empty(), error);
267   Release();  // Matches the AddRef in BeginInstall.
268 }
269
270 void
271 WebstoreStandaloneInstaller::ShowInstallUI() {
272   std::string error;
273   localized_extension_for_display_ =
274       ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
275           manifest_.get(),
276           Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
277           id_,
278           localized_name_,
279           localized_description_,
280           &error);
281   if (!localized_extension_for_display_.get()) {
282     CompleteInstall(kInvalidManifestError);
283     return;
284   }
285
286   // Keep this alive as long as the install prompt lives.
287   // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
288   // OnExtensionInstallSuccess or OnExtensionInstallFailure.
289   AddRef();
290
291   install_ui_ = CreateInstallUI();
292   install_ui_->ConfirmStandaloneInstall(
293       this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
294 }
295
296 }  // namespace extensions