blob: cacb466cc16886325b9b52679c2cfdfd79115ed3 [file] [log] [blame]
[email protected]c82da8c42012-06-08 19:49:111// 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/extension_install_prompt.h"
6
7#include <map>
8
9#include "base/command_line.h"
10#include "base/file_util.h"
11#include "base/message_loop.h"
[email protected]3853a4c2013-02-11 17:15:5712#include "base/prefs/pref_service.h"
[email protected]c82da8c42012-06-08 19:49:1113#include "base/string_util.h"
14#include "base/stringprintf.h"
[email protected]3ea1b182013-02-08 22:38:4115#include "base/strings/string_number_conversions.h"
[email protected]c82da8c42012-06-08 19:49:1116#include "base/utf_string_conversions.h"
17#include "chrome/browser/extensions/bundle_installer.h"
[email protected]c82da8c42012-06-08 19:49:1118#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]ec7de0c5a2012-11-16 07:40:4719#include "chrome/browser/extensions/image_loader.h"
[email protected]c82da8c42012-06-08 19:49:1120#include "chrome/browser/profiles/profile.h"
[email protected]b70a2d92012-06-28 19:51:2121#include "chrome/browser/signin/token_service.h"
22#include "chrome/browser/signin/token_service_factory.h"
[email protected]32fc4ff72012-06-15 21:50:0123#include "chrome/browser/ui/browser.h"
[email protected]619f86182012-07-03 21:30:1824#include "chrome/browser/ui/browser_window.h"
[email protected]c82da8c42012-06-08 19:49:1125#include "chrome/common/chrome_switches.h"
[email protected]29e0c4e72013-02-01 04:42:5626#include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
[email protected]c82da8c42012-06-08 19:49:1127#include "chrome/common/extensions/extension.h"
[email protected]faf87192012-08-17 00:07:5928#include "chrome/common/extensions/extension_constants.h"
[email protected]c82da8c42012-06-08 19:49:1129#include "chrome/common/extensions/extension_icon_set.h"
30#include "chrome/common/extensions/extension_manifest_constants.h"
31#include "chrome/common/extensions/extension_resource.h"
[email protected]544471a2012-10-13 05:27:0932#include "chrome/common/extensions/feature_switch.h"
[email protected]1d5e58b2013-01-31 08:41:4033#include "chrome/common/extensions/manifest.h"
[email protected]bebe1d02012-08-02 20:17:0934#include "chrome/common/extensions/permissions/permission_set.h"
[email protected]fc5077942012-08-15 21:37:5935#include "chrome/common/pref_names.h"
[email protected]91e51d612012-10-21 23:03:0536#include "content/public/browser/web_contents.h"
[email protected]5db2e882012-12-20 10:17:2637#include "content/public/browser/web_contents_view.h"
[email protected]885c0e92012-11-13 20:27:4238#include "extensions/common/url_pattern.h"
[email protected]c82da8c42012-06-08 19:49:1139#include "grit/chromium_strings.h"
40#include "grit/generated_resources.h"
[email protected]2a281332012-07-11 22:20:2341#include "grit/theme_resources.h"
[email protected]c82da8c42012-06-08 19:49:1142#include "ui/base/l10n/l10n_util.h"
43#include "ui/base/resource/resource_bundle.h"
44#include "ui/gfx/image/image.h"
45
[email protected]c82da8c42012-06-08 19:49:1146using extensions::BundleInstaller;
47using extensions::Extension;
[email protected]1d5e58b2013-01-31 08:41:4048using extensions::Manifest;
[email protected]c2e66e12012-06-27 06:27:0649using extensions::PermissionSet;
[email protected]c82da8c42012-06-08 19:49:1150
[email protected]612a1cb12012-10-17 13:18:0351namespace {
52
[email protected]c82da8c42012-06-08 19:49:1153static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
54 0, // The regular install prompt depends on what's being installed.
55 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
56 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
57 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
[email protected]612a1cb12012-10-17 13:18:0358 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
59 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
[email protected]15d267b42013-02-14 23:43:3260 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
[email protected]c82da8c42012-06-08 19:49:1161};
62static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
63 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
64 0, // Inline installs use the extension name.
65 0, // Heading for bundle installs depends on the bundle contents.
66 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
[email protected]612a1cb12012-10-17 13:18:0367 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
[email protected]846606012012-10-19 18:42:2568 0, // External installs use different strings for extensions/apps.
[email protected]15d267b42013-02-14 23:43:3269 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
70};
71static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
72 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
73 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
74 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
75 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
76 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
77 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
78 ui::DIALOG_BUTTON_CANCEL,
[email protected]c82da8c42012-06-08 19:49:1179};
80static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
81 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
82 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
83 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
84 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
[email protected]612a1cb12012-10-17 13:18:0385 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
[email protected]846606012012-10-19 18:42:2586 0, // External installs use different strings for extensions/apps.
[email protected]15d267b42013-02-14 23:43:3287 0,
[email protected]c82da8c42012-06-08 19:49:1188};
89static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
90 0, // These all use the platform's default cancel label.
91 0,
92 0,
93 0,
[email protected]612a1cb12012-10-17 13:18:0394 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
95 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
[email protected]15d267b42013-02-14 23:43:3296 IDS_CLOSE,
[email protected]c82da8c42012-06-08 19:49:1197};
98static const int kPermissionsHeaderIds[
99 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
100 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
101 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
102 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
103 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
104 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
[email protected]612a1cb12012-10-17 13:18:03105 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
[email protected]15d267b42013-02-14 23:43:32106 IDS_EXTENSION_PROMPT_CAN_ACCESS,
[email protected]c82da8c42012-06-08 19:49:11107};
[email protected]612a1cb12012-10-17 13:18:03108static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
[email protected]fc5077942012-08-15 21:37:59109 IDS_EXTENSION_PROMPT_OAUTH_HEADER,
110 0, // Inline installs don't show OAuth permissions.
111 0, // Bundle installs don't show OAuth permissions.
112 IDS_EXTENSION_PROMPT_OAUTH_REENABLE_HEADER,
113 IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER,
[email protected]612a1cb12012-10-17 13:18:03114 // TODO(mpcomplete): Do we need this for external install UI? If we do,
115 // we need to update FetchOAuthIssueAdviceIfNeeded.
116 0,
[email protected]15d267b42013-02-14 23:43:32117 0,
[email protected]fc5077942012-08-15 21:37:59118};
[email protected]c82da8c42012-06-08 19:49:11119
[email protected]c82da8c42012-06-08 19:49:11120// Size of extension icon in top left of dialog.
121const int kIconSize = 69;
122
[email protected]dd46a4ce2012-09-15 10:50:50123// Returns pixel size under maximal scale factor for the icon whose device
124// independent size is |size_in_dip|
125int GetSizeForMaxScaleFactor(int size_in_dip) {
[email protected]059d76b2012-11-16 17:25:42126 float max_scale_factor_scale =
127 ui::GetScaleFactorScale(ui::GetMaxScaleFactor());
[email protected]dd46a4ce2012-09-15 10:50:50128 return static_cast<int>(size_in_dip * max_scale_factor_scale);
129}
130
131// Returns bitmap for the default icon with size equal to the default icon's
132// pixel size under maximal supported scale factor.
133SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
[email protected]dd46a4ce2012-09-15 10:50:50134 return Extension::GetDefaultIcon(is_app).
[email protected]059d76b2012-11-16 17:25:42135 GetRepresentation(ui::GetMaxScaleFactor()).sk_bitmap();
[email protected]dd46a4ce2012-09-15 10:50:50136}
137
[email protected]af6efb22012-10-12 02:23:05138// If auto confirm is enabled then posts a task to proceed with or cancel the
139// install and returns true. Otherwise returns false.
140bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
141 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
142 if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests))
143 return false;
144 std::string value = cmdline->GetSwitchValueASCII(
145 switches::kAppsGalleryInstallAutoConfirmForTests);
146
147 // We use PostTask instead of calling the delegate directly here, because in
148 // the real implementations it's highly likely the message loop will be
149 // pumping a few times before the user clicks accept or cancel.
150 if (value == "accept") {
151 MessageLoop::current()->PostTask(
152 FROM_HERE,
153 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
154 base::Unretained(delegate)));
155 return true;
156 }
157
158 if (value == "cancel") {
159 MessageLoop::current()->PostTask(
160 FROM_HERE,
161 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
162 base::Unretained(delegate),
163 true));
164 return true;
165 }
166
167 NOTREACHED();
168 return false;
169}
170
[email protected]91e51d612012-10-21 23:03:05171Profile* ProfileForWebContents(content::WebContents* web_contents) {
172 if (!web_contents)
173 return NULL;
174 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
175}
176
[email protected]5db2e882012-12-20 10:17:26177gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
178 if (!contents)
179 return NULL;
180
181 return contents->GetView()->GetTopLevelNativeWindow();
182}
183
[email protected]c82da8c42012-06-08 19:49:11184} // namespace
185
[email protected]5db2e882012-12-20 10:17:26186ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
[email protected]c82da8c42012-06-08 19:49:11187 : type_(type),
188 extension_(NULL),
189 bundle_(NULL),
190 average_rating_(0.0),
[email protected]5db2e882012-12-20 10:17:26191 rating_count_(0) {
[email protected]c82da8c42012-06-08 19:49:11192}
193
194ExtensionInstallPrompt::Prompt::~Prompt() {
195}
196
197void ExtensionInstallPrompt::Prompt::SetPermissions(
198 const std::vector<string16>& permissions) {
199 permissions_ = permissions;
200}
201
[email protected]b70a2d92012-06-28 19:51:21202void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice(
203 const IssueAdviceInfo& issue_advice) {
204 oauth_issue_advice_ = issue_advice;
205}
206
[email protected]5db2e882012-12-20 10:17:26207void ExtensionInstallPrompt::Prompt::SetUserNameFromProfile(Profile* profile) {
208 // |profile| can be NULL in unit tests.
209 if (profile) {
210 oauth_user_name_ = UTF8ToUTF16(profile->GetPrefs()->GetString(
211 prefs::kGoogleServicesUsername));
212 } else {
213 oauth_user_name_.clear();
214 }
215}
216
[email protected]c82da8c42012-06-08 19:49:11217void ExtensionInstallPrompt::Prompt::SetInlineInstallWebstoreData(
218 const std::string& localized_user_count,
219 double average_rating,
220 int rating_count) {
221 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
222 localized_user_count_ = localized_user_count;
223 average_rating_ = average_rating;
224 rating_count_ = rating_count;
225}
226
227string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
[email protected]c82da8c42012-06-08 19:49:11228 int resource_id = kTitleIds[type_];
229
230 if (type_ == INSTALL_PROMPT) {
231 if (extension_->is_app())
232 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
233 else if (extension_->is_theme())
234 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
235 else
236 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
[email protected]612a1cb12012-10-17 13:18:03237 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
238 return l10n_util::GetStringFUTF16(
239 resource_id, UTF8ToUTF16(extension_->name()));
[email protected]c82da8c42012-06-08 19:49:11240 }
241
242 return l10n_util::GetStringUTF16(resource_id);
243}
244
245string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
246 if (type_ == INLINE_INSTALL_PROMPT) {
247 return UTF8ToUTF16(extension_->name());
248 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
249 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
[email protected]612a1cb12012-10-17 13:18:03250 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
[email protected]846606012012-10-19 18:42:25251 int resource_id = -1;
252 if (extension_->is_app())
253 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
254 else if (extension_->is_theme())
255 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
256 else
257 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
258 return l10n_util::GetStringUTF16(resource_id);
[email protected]c82da8c42012-06-08 19:49:11259 } else {
260 return l10n_util::GetStringFUTF16(
261 kHeadingIds[type_], UTF8ToUTF16(extension_->name()));
262 }
263}
264
[email protected]15d267b42013-02-14 23:43:32265int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
266 return kButtons[type_];
267}
268
269bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
270 return kAcceptButtonIds[type_] > 0;
271}
272
[email protected]c82da8c42012-06-08 19:49:11273string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
[email protected]846606012012-10-19 18:42:25274 if (type_ == EXTERNAL_INSTALL_PROMPT) {
275 int id = -1;
276 if (extension_->is_app())
277 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
278 else if (extension_->is_theme())
279 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
280 else
281 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
282 return l10n_util::GetStringUTF16(id);
283 }
[email protected]c82da8c42012-06-08 19:49:11284 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
285}
286
287bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
288 return kAbortButtonIds[type_] > 0;
289}
290
291string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
292 CHECK(HasAbortButtonLabel());
293 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
294}
295
296string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
297 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
298}
299
[email protected]813475e2012-07-02 23:54:18300string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
[email protected]5db2e882012-12-20 10:17:26301 return l10n_util::GetStringFUTF16(kOAuthHeaderIds[type_], oauth_user_name_);
[email protected]813475e2012-07-02 23:54:18302}
303
[email protected]c82da8c42012-06-08 19:49:11304void ExtensionInstallPrompt::Prompt::AppendRatingStars(
305 StarAppender appender, void* data) const {
306 CHECK(appender);
307 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
308 int rating_integer = floor(average_rating_);
309 double rating_fractional = average_rating_ - rating_integer;
310
311 if (rating_fractional > 0.66) {
312 rating_integer++;
313 }
314
315 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
316 rating_fractional = 0;
317 }
318
319 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
320 int i;
321 for (i = 0; i < rating_integer; i++) {
322 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
323 }
324 if (rating_fractional) {
325 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
326 i++;
327 }
328 for (; i < kMaxExtensionRating; i++) {
329 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
330 }
331}
332
333string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
334 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
335 return l10n_util::GetStringFUTF16(
336 IDS_EXTENSION_RATING_COUNT,
337 UTF8ToUTF16(base::IntToString(rating_count_)));
338}
339
340string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
341 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
342 return l10n_util::GetStringFUTF16(
343 IDS_EXTENSION_USER_COUNT,
344 UTF8ToUTF16(localized_user_count_));
345}
346
347size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
348 return permissions_.size();
349}
350
351string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index) const {
352 CHECK_LT(index, permissions_.size());
[email protected]ef2654e42012-08-11 03:57:56353 return permissions_[index];
[email protected]c82da8c42012-06-08 19:49:11354}
355
[email protected]b70a2d92012-06-28 19:51:21356size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
357 return oauth_issue_advice_.size();
358}
359
360const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue(
361 size_t index) const {
362 CHECK_LT(index, oauth_issue_advice_.size());
363 return oauth_issue_advice_[index];
364}
365
[email protected]5db2e882012-12-20 10:17:26366ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
367 : parent_web_contents(contents),
368 parent_window(NativeWindowForWebContents(contents)),
369 navigator(contents) {
370}
371
372ExtensionInstallPrompt::ShowParams::ShowParams(
373 gfx::NativeWindow window,
374 content::PageNavigator* navigator)
375 : parent_web_contents(NULL),
376 parent_window(window),
377 navigator(navigator) {
378}
379
[email protected]c82da8c42012-06-08 19:49:11380// static
381scoped_refptr<Extension>
382 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
383 const DictionaryValue* manifest,
[email protected]c422a862012-07-31 15:46:13384 int flags,
[email protected]c82da8c42012-06-08 19:49:11385 const std::string& id,
386 const std::string& localized_name,
387 const std::string& localized_description,
388 std::string* error) {
389 scoped_ptr<DictionaryValue> localized_manifest;
390 if (!localized_name.empty() || !localized_description.empty()) {
391 localized_manifest.reset(manifest->DeepCopy());
392 if (!localized_name.empty()) {
393 localized_manifest->SetString(extension_manifest_keys::kName,
394 localized_name);
395 }
396 if (!localized_description.empty()) {
397 localized_manifest->SetString(extension_manifest_keys::kDescription,
398 localized_description);
399 }
400 }
401
402 return Extension::Create(
[email protected]650b2d52013-02-10 03:41:45403 base::FilePath(),
[email protected]1d5e58b2013-01-31 08:41:40404 Manifest::INTERNAL,
[email protected]c82da8c42012-06-08 19:49:11405 localized_manifest.get() ? *localized_manifest.get() : *manifest,
[email protected]c422a862012-07-31 15:46:13406 flags,
[email protected]c82da8c42012-06-08 19:49:11407 id,
408 error);
409}
410
[email protected]619f86182012-07-03 21:30:18411ExtensionInstallPrompt::ExtensionInstallPrompt(
[email protected]91e51d612012-10-21 23:03:05412 content::WebContents* contents)
[email protected]16798da832012-08-30 20:46:04413 : record_oauth2_grant_(false),
[email protected]c82da8c42012-06-08 19:49:11414 ui_loop_(MessageLoop::current()),
415 extension_(NULL),
[email protected]91e51d612012-10-21 23:03:05416 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))),
[email protected]5db2e882012-12-20 10:17:26417 show_params_(contents),
[email protected]c82da8c42012-06-08 19:49:11418 delegate_(NULL),
[email protected]5db2e882012-12-20 10:17:26419 prompt_(UNSET_PROMPT_TYPE) {
420 prompt_.SetUserNameFromProfile(install_ui_->profile());
421}
422
423ExtensionInstallPrompt::ExtensionInstallPrompt(
424 Profile* profile,
425 gfx::NativeWindow native_window,
426 content::PageNavigator* navigator)
427 : record_oauth2_grant_(false),
428 ui_loop_(MessageLoop::current()),
429 extension_(NULL),
430 install_ui_(ExtensionInstallUI::Create(profile)),
431 show_params_(native_window, navigator),
432 delegate_(NULL),
433 prompt_(UNSET_PROMPT_TYPE) {
434 prompt_.SetUserNameFromProfile(install_ui_->profile());
[email protected]c82da8c42012-06-08 19:49:11435}
436
437ExtensionInstallPrompt::~ExtensionInstallPrompt() {
438}
439
440void ExtensionInstallPrompt::ConfirmBundleInstall(
441 extensions::BundleInstaller* bundle,
[email protected]c2e66e12012-06-27 06:27:06442 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11443 DCHECK(ui_loop_ == MessageLoop::current());
444 bundle_ = bundle;
445 permissions_ = permissions;
446 delegate_ = bundle;
[email protected]5db2e882012-12-20 10:17:26447 prompt_.set_type(BUNDLE_INSTALL_PROMPT);
[email protected]c82da8c42012-06-08 19:49:11448
[email protected]b70a2d92012-06-28 19:51:21449 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11450}
451
[email protected]734bcec2012-10-08 20:29:05452void ExtensionInstallPrompt::ConfirmStandaloneInstall(
[email protected]c82da8c42012-06-08 19:49:11453 Delegate* delegate,
454 const Extension* extension,
455 SkBitmap* icon,
456 const ExtensionInstallPrompt::Prompt& prompt) {
457 DCHECK(ui_loop_ == MessageLoop::current());
458 extension_ = extension;
459 permissions_ = extension->GetActivePermissions();
460 delegate_ = delegate;
461 prompt_ = prompt;
[email protected]c82da8c42012-06-08 19:49:11462
463 SetIcon(icon);
[email protected]b70a2d92012-06-28 19:51:21464 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11465}
466
[email protected]af6efb22012-10-12 02:23:05467void ExtensionInstallPrompt::ConfirmWebstoreInstall(
468 Delegate* delegate,
469 const Extension* extension,
470 const SkBitmap* icon,
471 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11472 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
473 // remaining fields.
474 extension_ = extension;
475 SetIcon(icon);
[email protected]af6efb22012-10-12 02:23:05476 ConfirmInstall(delegate, extension, show_dialog_callback);
[email protected]c82da8c42012-06-08 19:49:11477}
478
[email protected]af6efb22012-10-12 02:23:05479void ExtensionInstallPrompt::ConfirmInstall(
480 Delegate* delegate,
481 const Extension* extension,
482 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11483 DCHECK(ui_loop_ == MessageLoop::current());
484 extension_ = extension;
485 permissions_ = extension->GetActivePermissions();
486 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26487 prompt_.set_type(INSTALL_PROMPT);
[email protected]af6efb22012-10-12 02:23:05488 show_dialog_callback_ = show_dialog_callback;
[email protected]c82da8c42012-06-08 19:49:11489
490 // We special-case themes to not show any confirm UI. Instead they are
491 // immediately installed, and then we show an infobar (see OnInstallSuccess)
492 // to allow the user to revert if they don't like it.
493 //
494 // We don't do this in the case where off-store extension installs are
495 // disabled because in that case, we don't show the dangerous download UI, so
496 // we need the UI confirmation.
497 if (extension->is_theme()) {
498 if (extension->from_webstore() ||
[email protected]544471a2012-10-13 05:27:09499 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
[email protected]c82da8c42012-06-08 19:49:11500 delegate->InstallUIProceed();
501 return;
502 }
503 }
504
505 LoadImageIfNeeded();
506}
507
508void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
509 const Extension* extension) {
510 DCHECK(ui_loop_ == MessageLoop::current());
511 extension_ = extension;
512 permissions_ = extension->GetActivePermissions();
513 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26514 prompt_.set_type(RE_ENABLE_PROMPT);
[email protected]c82da8c42012-06-08 19:49:11515
516 LoadImageIfNeeded();
517}
518
[email protected]612a1cb12012-10-17 13:18:03519void ExtensionInstallPrompt::ConfirmExternalInstall(
520 Delegate* delegate, const Extension* extension) {
521 DCHECK(ui_loop_ == MessageLoop::current());
522 extension_ = extension;
523 permissions_ = extension->GetActivePermissions();
524 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26525 prompt_.set_type(EXTERNAL_INSTALL_PROMPT);
[email protected]612a1cb12012-10-17 13:18:03526
527 LoadImageIfNeeded();
528}
529
[email protected]c82da8c42012-06-08 19:49:11530void ExtensionInstallPrompt::ConfirmPermissions(
531 Delegate* delegate,
532 const Extension* extension,
[email protected]c2e66e12012-06-27 06:27:06533 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11534 DCHECK(ui_loop_ == MessageLoop::current());
535 extension_ = extension;
536 permissions_ = permissions;
537 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26538 prompt_.set_type(PERMISSIONS_PROMPT);
[email protected]c82da8c42012-06-08 19:49:11539
540 LoadImageIfNeeded();
541}
542
[email protected]f746b3f2012-07-03 17:53:37543void ExtensionInstallPrompt::ConfirmIssueAdvice(
544 Delegate* delegate,
545 const Extension* extension,
546 const IssueAdviceInfo& issue_advice) {
547 DCHECK(ui_loop_ == MessageLoop::current());
548 extension_ = extension;
549 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26550 prompt_.set_type(PERMISSIONS_PROMPT);
[email protected]f746b3f2012-07-03 17:53:37551
552 record_oauth2_grant_ = true;
553 prompt_.SetOAuthIssueAdvice(issue_advice);
554
555 LoadImageIfNeeded();
556}
557
[email protected]15d267b42013-02-14 23:43:32558void ExtensionInstallPrompt::ReviewPermissions(Delegate* delegate,
559 const Extension* extension) {
560 DCHECK(ui_loop_ == MessageLoop::current());
561 extension_ = extension;
562 permissions_ = extension->GetActivePermissions();
563 delegate_ = delegate;
564 prompt_.set_type(POST_INSTALL_PERMISSIONS_PROMPT);
565
566 LoadImageIfNeeded();
567}
568
[email protected]c82da8c42012-06-08 19:49:11569void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
570 SkBitmap* icon) {
571 extension_ = extension;
572 SetIcon(icon);
573
574 install_ui_->OnInstallSuccess(extension, &icon_);
575}
576
[email protected]bf3d9df2012-07-24 23:20:27577void ExtensionInstallPrompt::OnInstallFailure(
578 const extensions::CrxInstallerError& error) {
[email protected]c82da8c42012-06-08 19:49:11579 install_ui_->OnInstallFailure(error);
580}
581
582void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
583 if (image)
584 icon_ = *image;
585 else
586 icon_ = SkBitmap();
[email protected]dd46a4ce2012-09-15 10:50:50587 if (icon_.empty()) {
588 // Let's set default icon bitmap whose size is equal to the default icon's
589 // pixel size under maximal supported scale factor. If the bitmap is larger
590 // than the one we need, it will be scaled down by the ui code.
591 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
592 }
[email protected]c82da8c42012-06-08 19:49:11593}
594
[email protected]ec7de0c5a2012-11-16 07:40:47595void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
[email protected]c82da8c42012-06-08 19:49:11596 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
[email protected]b70a2d92012-06-28 19:51:21597 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11598}
599
600void ExtensionInstallPrompt::LoadImageIfNeeded() {
601 // Bundle install prompts do not have an icon.
[email protected]5db2e882012-12-20 10:17:26602 // Also |install_ui_.profile()| can be NULL in unit tests.
603 if (!icon_.empty() || !install_ui_->profile()) {
[email protected]b70a2d92012-06-28 19:51:21604 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11605 return;
606 }
607
608 // Load the image asynchronously. For the response, check OnImageLoaded.
609 ExtensionResource image =
[email protected]faf87192012-08-17 00:07:59610 extension_->GetIconResource(extension_misc::EXTENSION_ICON_LARGE,
[email protected]c82da8c42012-06-08 19:49:11611 ExtensionIconSet::MATCH_BIGGER);
[email protected]dd46a4ce2012-09-15 10:50:50612 // Load the icon whose pixel size is large enough to be displayed under
613 // maximal supported scale factor. UI code will scale the icon down if needed.
614 // TODO(tbarzic): We should use IconImage here and load the required bitmap
615 // lazily.
616 int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
[email protected]5db2e882012-12-20 10:17:26617 extensions::ImageLoader::Get(install_ui_->profile())->LoadImageAsync(
[email protected]ec7de0c5a2012-11-16 07:40:47618 extension_, image, gfx::Size(pixel_size, pixel_size),
619 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
[email protected]c82da8c42012-06-08 19:49:11620}
621
[email protected]b70a2d92012-06-28 19:51:21622void ExtensionInstallPrompt::FetchOAuthIssueAdviceIfNeeded() {
[email protected]668ed2c2012-09-12 10:52:41623 // |extension_| may be NULL, e.g. in the bundle install case.
624 if (!extension_ ||
[email protected]5db2e882012-12-20 10:17:26625 prompt_.type() == BUNDLE_INSTALL_PROMPT ||
626 prompt_.type() == INLINE_INSTALL_PROMPT ||
627 prompt_.type() == EXTERNAL_INSTALL_PROMPT ||
[email protected]668ed2c2012-09-12 10:52:41628 prompt_.GetOAuthIssueCount() != 0U) {
629 ShowConfirmation();
630 return;
631 }
632
[email protected]29e0c4e72013-02-01 04:42:56633 const extensions::OAuth2Info& oauth2_info =
634 extensions::OAuth2Info::GetOAuth2Info(extension_);
[email protected]668ed2c2012-09-12 10:52:41635 if (oauth2_info.client_id.empty() ||
636 oauth2_info.scopes.empty()) {
[email protected]b70a2d92012-06-28 19:51:21637 ShowConfirmation();
638 return;
639 }
640
[email protected]7cac5262012-09-26 17:32:25641 Profile* profile = install_ui_->profile();
[email protected]b70a2d92012-06-28 19:51:21642 TokenService* token_service = TokenServiceFactory::GetForProfile(profile);
[email protected]b70a2d92012-06-28 19:51:21643
644 token_flow_.reset(new OAuth2MintTokenFlow(
645 profile->GetRequestContext(),
646 this,
647 OAuth2MintTokenFlow::Parameters(
648 token_service->GetOAuth2LoginRefreshToken(),
649 extension_->id(),
650 oauth2_info.client_id,
[email protected]d4a37f1c2012-07-09 21:36:13651 oauth2_info.scopes,
[email protected]b70a2d92012-06-28 19:51:21652 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE)));
653 token_flow_->Start();
654}
655
656void ExtensionInstallPrompt::OnIssueAdviceSuccess(
657 const IssueAdviceInfo& advice_info) {
658 prompt_.SetOAuthIssueAdvice(advice_info);
659 record_oauth2_grant_ = true;
660 ShowConfirmation();
661}
662
663void ExtensionInstallPrompt::OnMintTokenFailure(
664 const GoogleServiceAuthError& error) {
665 ShowConfirmation();
666}
667
[email protected]c82da8c42012-06-08 19:49:11668void ExtensionInstallPrompt::ShowConfirmation() {
[email protected]b0d1d0b2012-11-02 21:19:03669 if (permissions_ &&
670 (!extension_ || !extension_->ShouldSkipPermissionWarnings())) {
[email protected]1d5e58b2013-01-31 08:41:40671 Manifest::Type extension_type = extension_ ?
672 extension_->GetType() : Manifest::TYPE_UNKNOWN;
[email protected]a6e5c9b2012-08-09 04:06:25673 prompt_.SetPermissions(permissions_->GetWarningMessages(extension_type));
[email protected]bebe1d02012-08-02 20:17:09674 }
[email protected]c82da8c42012-06-08 19:49:11675
[email protected]5db2e882012-12-20 10:17:26676 switch (prompt_.type()) {
[email protected]c82da8c42012-06-08 19:49:11677 case PERMISSIONS_PROMPT:
678 case RE_ENABLE_PROMPT:
679 case INLINE_INSTALL_PROMPT:
[email protected]612a1cb12012-10-17 13:18:03680 case EXTERNAL_INSTALL_PROMPT:
[email protected]15d267b42013-02-14 23:43:32681 case INSTALL_PROMPT:
682 case POST_INSTALL_PERMISSIONS_PROMPT: {
[email protected]c82da8c42012-06-08 19:49:11683 prompt_.set_extension(extension_);
[email protected]32e7a9b2013-01-23 23:00:19684 prompt_.set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
[email protected]c82da8c42012-06-08 19:49:11685 break;
686 }
687 case BUNDLE_INSTALL_PROMPT: {
688 prompt_.set_bundle(bundle_);
[email protected]c82da8c42012-06-08 19:49:11689 break;
690 }
691 default:
692 NOTREACHED() << "Unknown message";
[email protected]af6efb22012-10-12 02:23:05693 return;
[email protected]c82da8c42012-06-08 19:49:11694 }
[email protected]af6efb22012-10-12 02:23:05695
696 if (AutoConfirmPrompt(delegate_))
697 return;
698
[email protected]5db2e882012-12-20 10:17:26699 if (show_dialog_callback_.is_null())
700 GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
701 else
702 show_dialog_callback_.Run(show_params_, delegate_, prompt_);
[email protected]c82da8c42012-06-08 19:49:11703}