NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / extensions / extension_install_prompt.cc
blob983b3bbaae51c385ae0c19ad6276caddd60fd420
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/extension_install_prompt.h"
7 #include <map>
9 #include "base/command_line.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/extensions/bundle_installer.h"
17 #include "chrome/browser/extensions/extension_install_ui.h"
18 #include "chrome/browser/extensions/image_loader.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/signin/profile_oauth2_token_service.h"
21 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_window.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
26 #include "chrome/common/extensions/extension_constants.h"
27 #include "chrome/common/extensions/extension_icon_set.h"
28 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
29 #include "chrome/common/pref_names.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/browser/web_contents_view.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/extension_resource.h"
34 #include "extensions/common/feature_switch.h"
35 #include "extensions/common/manifest.h"
36 #include "extensions/common/manifest_constants.h"
37 #include "extensions/common/permissions/permission_message_provider.h"
38 #include "extensions/common/permissions/permission_set.h"
39 #include "extensions/common/permissions/permissions_data.h"
40 #include "extensions/common/url_pattern.h"
41 #include "grit/chromium_strings.h"
42 #include "grit/generated_resources.h"
43 #include "grit/theme_resources.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/gfx/image/image.h"
48 using extensions::BundleInstaller;
49 using extensions::Extension;
50 using extensions::Manifest;
51 using extensions::PermissionSet;
53 namespace {
55 static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
56 0, // The regular install prompt depends on what's being installed.
57 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
58 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
59 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
60 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
61 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
62 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
63 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE,
65 static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
66 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
67 0, // Inline installs use the extension name.
68 0, // Heading for bundle installs depends on the bundle contents.
69 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
70 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
71 0, // External installs use different strings for extensions/apps.
72 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
73 IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING,
75 static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
76 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
77 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
78 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
79 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
80 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
81 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
82 ui::DIALOG_BUTTON_CANCEL,
83 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
85 static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
86 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
87 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
88 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
89 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
90 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
91 0, // External installs use different strings for extensions/apps.
92 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON,
93 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON,
95 static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
96 0, // These all use the platform's default cancel label.
100 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
101 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
102 IDS_CLOSE,
103 0, // Platform dependent cancel button.
105 static const int kPermissionsHeaderIds[
106 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
107 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
108 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
109 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
110 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
111 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
112 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
113 IDS_EXTENSION_PROMPT_CAN_ACCESS,
114 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
116 static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
117 IDS_EXTENSION_PROMPT_OAUTH_HEADER,
118 0, // Inline installs don't show OAuth permissions.
119 0, // Bundle installs don't show OAuth permissions.
120 IDS_EXTENSION_PROMPT_OAUTH_REENABLE_HEADER,
121 IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER,
124 IDS_EXTENSION_PROMPT_OAUTH_HEADER,
127 // Size of extension icon in top left of dialog.
128 const int kIconSize = 69;
130 // Returns pixel size under maximal scale factor for the icon whose device
131 // independent size is |size_in_dip|
132 int GetSizeForMaxScaleFactor(int size_in_dip) {
133 return static_cast<int>(size_in_dip * gfx::ImageSkia::GetMaxSupportedScale());
136 // Returns bitmap for the default icon with size equal to the default icon's
137 // pixel size under maximal supported scale factor.
138 SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
139 const gfx::ImageSkia& image = is_app ?
140 extensions::IconsInfo::GetDefaultAppIcon() :
141 extensions::IconsInfo::GetDefaultExtensionIcon();
142 return image.GetRepresentation(
143 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
146 // If auto confirm is enabled then posts a task to proceed with or cancel the
147 // install and returns true. Otherwise returns false.
148 bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
149 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
150 if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests))
151 return false;
152 std::string value = cmdline->GetSwitchValueASCII(
153 switches::kAppsGalleryInstallAutoConfirmForTests);
155 // We use PostTask instead of calling the delegate directly here, because in
156 // the real implementations it's highly likely the message loop will be
157 // pumping a few times before the user clicks accept or cancel.
158 if (value == "accept") {
159 base::MessageLoop::current()->PostTask(
160 FROM_HERE,
161 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
162 base::Unretained(delegate)));
163 return true;
166 if (value == "cancel") {
167 base::MessageLoop::current()->PostTask(
168 FROM_HERE,
169 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
170 base::Unretained(delegate),
171 true));
172 return true;
175 NOTREACHED();
176 return false;
179 Profile* ProfileForWebContents(content::WebContents* web_contents) {
180 if (!web_contents)
181 return NULL;
182 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
185 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
186 if (!contents)
187 return NULL;
189 return contents->GetView()->GetTopLevelNativeWindow();
192 } // namespace
194 ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
195 : type_(type),
196 is_showing_details_for_retained_files_(false),
197 extension_(NULL),
198 bundle_(NULL),
199 average_rating_(0.0),
200 rating_count_(0),
201 show_user_count_(false),
202 has_webstore_data_(false) {
205 ExtensionInstallPrompt::Prompt::~Prompt() {
208 void ExtensionInstallPrompt::Prompt::SetPermissions(
209 const std::vector<base::string16>& permissions) {
210 permissions_ = permissions;
213 void ExtensionInstallPrompt::Prompt::SetPermissionsDetails(
214 const std::vector<base::string16>& details) {
215 details_ = details;
216 is_showing_details_for_permissions_.clear();
217 for (size_t i = 0; i < details.size(); ++i)
218 is_showing_details_for_permissions_.push_back(false);
221 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
222 DetailsType type,
223 size_t index,
224 bool is_showing_details) {
225 switch (type) {
226 case PERMISSIONS_DETAILS:
227 is_showing_details_for_permissions_[index] = is_showing_details;
228 break;
229 case OAUTH_DETAILS:
230 is_showing_details_for_oauth_[index] = is_showing_details;
231 break;
232 case RETAINED_FILES_DETAILS:
233 is_showing_details_for_retained_files_ = is_showing_details;
234 break;
238 void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice(
239 const IssueAdviceInfo& issue_advice) {
240 is_showing_details_for_oauth_.clear();
241 for (size_t i = 0; i < issue_advice.size(); ++i)
242 is_showing_details_for_oauth_.push_back(false);
244 oauth_issue_advice_ = issue_advice;
247 void ExtensionInstallPrompt::Prompt::SetUserNameFromProfile(Profile* profile) {
248 // |profile| can be NULL in unit tests.
249 if (profile) {
250 oauth_user_name_ = base::UTF8ToUTF16(profile->GetPrefs()->GetString(
251 prefs::kGoogleServicesUsername));
252 } else {
253 oauth_user_name_.clear();
257 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
258 const std::string& localized_user_count,
259 bool show_user_count,
260 double average_rating,
261 int rating_count) {
262 CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
263 localized_user_count_ = localized_user_count;
264 show_user_count_ = show_user_count;
265 average_rating_ = average_rating;
266 rating_count_ = rating_count;
267 has_webstore_data_ = true;
270 base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
271 int resource_id = kTitleIds[type_];
273 if (type_ == INSTALL_PROMPT) {
274 if (extension_->is_app())
275 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
276 else if (extension_->is_theme())
277 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
278 else
279 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
280 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
281 return l10n_util::GetStringFUTF16(
282 resource_id, base::UTF8ToUTF16(extension_->name()));
285 return l10n_util::GetStringUTF16(resource_id);
288 base::string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
289 if (type_ == INLINE_INSTALL_PROMPT) {
290 return base::UTF8ToUTF16(extension_->name());
291 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
292 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
293 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
294 int resource_id = -1;
295 if (extension_->is_app())
296 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
297 else if (extension_->is_theme())
298 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
299 else
300 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
301 return l10n_util::GetStringUTF16(resource_id);
302 } else {
303 return l10n_util::GetStringFUTF16(
304 kHeadingIds[type_], base::UTF8ToUTF16(extension_->name()));
308 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
309 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT &&
310 ShouldDisplayRevokeFilesButton()) {
311 return kButtons[type_] | ui::DIALOG_BUTTON_OK;
314 return kButtons[type_];
317 bool ExtensionInstallPrompt::Prompt::ShouldShowExplanationText() const {
318 return type_ == INSTALL_PROMPT &&
319 extension_->is_extension() && experiment_ && experiment_->text_only();
322 bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
323 if (kAcceptButtonIds[type_] == 0)
324 return false;
326 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT)
327 return ShouldDisplayRevokeFilesButton();
329 return true;
332 base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
333 if (type_ == EXTERNAL_INSTALL_PROMPT) {
334 int id = -1;
335 if (extension_->is_app())
336 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
337 else if (extension_->is_theme())
338 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
339 else
340 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
341 return l10n_util::GetStringUTF16(id);
343 if (ShouldShowExplanationText())
344 return experiment_->GetOkButtonText();
345 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
348 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
349 if (ShouldShowExplanationText())
350 return true;
351 return kAbortButtonIds[type_] > 0;
354 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
355 CHECK(HasAbortButtonLabel());
356 if (ShouldShowExplanationText())
357 return experiment_->GetCancelButtonText();
358 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
361 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
362 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
365 base::string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
366 return l10n_util::GetStringFUTF16(kOAuthHeaderIds[type_], oauth_user_name_);
369 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
370 const int kRetainedFilesMessageIDs[6] = {
371 IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT,
372 IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR,
373 IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO,
374 IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO,
375 IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW,
376 IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY,
378 std::vector<int> message_ids;
379 for (size_t i = 0; i < arraysize(kRetainedFilesMessageIDs); i++) {
380 message_ids.push_back(kRetainedFilesMessageIDs[i]);
382 return l10n_util::GetPluralStringFUTF16(message_ids, GetRetainedFileCount());
385 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
386 return GetPermissionCount() > 0 || type_ == POST_INSTALL_PERMISSIONS_PROMPT;
389 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
390 StarAppender appender, void* data) const {
391 CHECK(appender);
392 CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
393 int rating_integer = floor(average_rating_);
394 double rating_fractional = average_rating_ - rating_integer;
396 if (rating_fractional > 0.66) {
397 rating_integer++;
400 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
401 rating_fractional = 0;
404 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
405 int i;
406 for (i = 0; i < rating_integer; i++) {
407 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
409 if (rating_fractional) {
410 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
411 i++;
413 for (; i < kMaxExtensionRating; i++) {
414 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
418 base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
419 CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
420 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
421 base::IntToString16(rating_count_));
424 base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
425 CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
427 if (show_user_count_) {
428 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
429 base::UTF8ToUTF16(localized_user_count_));
431 return base::string16();
434 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
435 return permissions_.size();
438 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount() const {
439 return details_.size();
442 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index)
443 const {
444 CHECK_LT(index, permissions_.size());
445 return permissions_[index];
448 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
449 size_t index) const {
450 CHECK_LT(index, details_.size());
451 return details_[index];
454 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
455 DetailsType type, size_t index) const {
456 switch (type) {
457 case PERMISSIONS_DETAILS:
458 CHECK_LT(index, is_showing_details_for_permissions_.size());
459 return is_showing_details_for_permissions_[index];
460 case OAUTH_DETAILS:
461 CHECK_LT(index, is_showing_details_for_oauth_.size());
462 return is_showing_details_for_oauth_[index];
463 case RETAINED_FILES_DETAILS:
464 return is_showing_details_for_retained_files_;
466 return false;
469 size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
470 return oauth_issue_advice_.size();
473 const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue(
474 size_t index) const {
475 CHECK_LT(index, oauth_issue_advice_.size());
476 return oauth_issue_advice_[index];
479 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
480 return retained_files_.size();
483 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
484 const {
485 CHECK_LT(index, retained_files_.size());
486 return retained_files_[index].AsUTF16Unsafe();
489 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
490 return !retained_files_.empty();
493 ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
494 : parent_web_contents(contents),
495 parent_window(NativeWindowForWebContents(contents)),
496 navigator(contents) {
499 ExtensionInstallPrompt::ShowParams::ShowParams(
500 gfx::NativeWindow window,
501 content::PageNavigator* navigator)
502 : parent_web_contents(NULL),
503 parent_window(window),
504 navigator(navigator) {
507 // static
508 scoped_refptr<Extension>
509 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
510 const base::DictionaryValue* manifest,
511 int flags,
512 const std::string& id,
513 const std::string& localized_name,
514 const std::string& localized_description,
515 std::string* error) {
516 scoped_ptr<base::DictionaryValue> localized_manifest;
517 if (!localized_name.empty() || !localized_description.empty()) {
518 localized_manifest.reset(manifest->DeepCopy());
519 if (!localized_name.empty()) {
520 localized_manifest->SetString(extensions::manifest_keys::kName,
521 localized_name);
523 if (!localized_description.empty()) {
524 localized_manifest->SetString(extensions::manifest_keys::kDescription,
525 localized_description);
529 return Extension::Create(
530 base::FilePath(),
531 Manifest::INTERNAL,
532 localized_manifest.get() ? *localized_manifest.get() : *manifest,
533 flags,
535 error);
538 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents)
539 : OAuth2TokenService::Consumer("extensions_install"),
540 record_oauth2_grant_(false),
541 ui_loop_(base::MessageLoop::current()),
542 extension_(NULL),
543 bundle_(NULL),
544 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))),
545 show_params_(contents),
546 delegate_(NULL),
547 prompt_(UNSET_PROMPT_TYPE) {
548 prompt_.SetUserNameFromProfile(install_ui_->profile());
551 ExtensionInstallPrompt::ExtensionInstallPrompt(
552 Profile* profile,
553 gfx::NativeWindow native_window,
554 content::PageNavigator* navigator)
555 : OAuth2TokenService::Consumer("extensions_install"),
556 record_oauth2_grant_(false),
557 ui_loop_(base::MessageLoop::current()),
558 extension_(NULL),
559 bundle_(NULL),
560 install_ui_(ExtensionInstallUI::Create(profile)),
561 show_params_(native_window, navigator),
562 delegate_(NULL),
563 prompt_(UNSET_PROMPT_TYPE) {
564 prompt_.SetUserNameFromProfile(install_ui_->profile());
567 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
570 void ExtensionInstallPrompt::ConfirmBundleInstall(
571 extensions::BundleInstaller* bundle,
572 const PermissionSet* permissions) {
573 DCHECK(ui_loop_ == base::MessageLoop::current());
574 bundle_ = bundle;
575 permissions_ = permissions;
576 delegate_ = bundle;
577 prompt_.set_type(BUNDLE_INSTALL_PROMPT);
579 ShowConfirmation();
582 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
583 Delegate* delegate,
584 const Extension* extension,
585 SkBitmap* icon,
586 const ExtensionInstallPrompt::Prompt& prompt) {
587 DCHECK(ui_loop_ == base::MessageLoop::current());
588 extension_ = extension;
589 permissions_ = extension->GetActivePermissions();
590 delegate_ = delegate;
591 prompt_ = prompt;
593 SetIcon(icon);
594 ShowConfirmation();
597 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
598 Delegate* delegate,
599 const Extension* extension,
600 const SkBitmap* icon,
601 const ShowDialogCallback& show_dialog_callback) {
602 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
603 // remaining fields.
604 extension_ = extension;
605 SetIcon(icon);
606 ConfirmInstall(delegate, extension, show_dialog_callback);
609 void ExtensionInstallPrompt::ConfirmInstall(
610 Delegate* delegate,
611 const Extension* extension,
612 const ShowDialogCallback& show_dialog_callback) {
613 DCHECK(ui_loop_ == base::MessageLoop::current());
614 extension_ = extension;
615 permissions_ = extension->GetActivePermissions();
616 delegate_ = delegate;
617 prompt_.set_type(INSTALL_PROMPT);
618 show_dialog_callback_ = show_dialog_callback;
620 // We special-case themes to not show any confirm UI. Instead they are
621 // immediately installed, and then we show an infobar (see OnInstallSuccess)
622 // to allow the user to revert if they don't like it.
624 // We don't do this in the case where off-store extension installs are
625 // disabled because in that case, we don't show the dangerous download UI, so
626 // we need the UI confirmation.
627 if (extension->is_theme()) {
628 if (extension->from_webstore() ||
629 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
630 delegate->InstallUIProceed();
631 return;
635 LoadImageIfNeeded();
638 void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
639 const Extension* extension) {
640 DCHECK(ui_loop_ == base::MessageLoop::current());
641 extension_ = extension;
642 permissions_ = extension->GetActivePermissions();
643 delegate_ = delegate;
644 prompt_.set_type(extension->is_ephemeral() ? LAUNCH_PROMPT :
645 RE_ENABLE_PROMPT);
647 LoadImageIfNeeded();
650 void ExtensionInstallPrompt::ConfirmExternalInstall(
651 Delegate* delegate,
652 const Extension* extension,
653 const ShowDialogCallback& show_dialog_callback,
654 const Prompt& prompt) {
655 DCHECK(ui_loop_ == base::MessageLoop::current());
656 extension_ = extension;
657 permissions_ = extension->GetActivePermissions();
658 delegate_ = delegate;
659 prompt_ = prompt;
660 show_dialog_callback_ = show_dialog_callback;
662 LoadImageIfNeeded();
665 void ExtensionInstallPrompt::ConfirmPermissions(
666 Delegate* delegate,
667 const Extension* extension,
668 const PermissionSet* permissions) {
669 DCHECK(ui_loop_ == base::MessageLoop::current());
670 extension_ = extension;
671 permissions_ = permissions;
672 delegate_ = delegate;
673 prompt_.set_type(PERMISSIONS_PROMPT);
675 LoadImageIfNeeded();
678 void ExtensionInstallPrompt::ConfirmIssueAdvice(
679 Delegate* delegate,
680 const Extension* extension,
681 const IssueAdviceInfo& issue_advice) {
682 DCHECK(ui_loop_ == base::MessageLoop::current());
683 extension_ = extension;
684 delegate_ = delegate;
685 prompt_.set_type(PERMISSIONS_PROMPT);
687 record_oauth2_grant_ = true;
688 prompt_.SetOAuthIssueAdvice(issue_advice);
690 LoadImageIfNeeded();
693 void ExtensionInstallPrompt::ReviewPermissions(
694 Delegate* delegate,
695 const Extension* extension,
696 const std::vector<base::FilePath>& retained_file_paths) {
697 DCHECK(ui_loop_ == base::MessageLoop::current());
698 extension_ = extension;
699 permissions_ = extension->GetActivePermissions();
700 prompt_.set_retained_files(retained_file_paths);
701 delegate_ = delegate;
702 prompt_.set_type(POST_INSTALL_PERMISSIONS_PROMPT);
704 LoadImageIfNeeded();
707 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
708 SkBitmap* icon) {
709 extension_ = extension;
710 SetIcon(icon);
712 install_ui_->OnInstallSuccess(extension, &icon_);
715 void ExtensionInstallPrompt::OnInstallFailure(
716 const extensions::CrxInstallerError& error) {
717 install_ui_->OnInstallFailure(error);
720 void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
721 if (image)
722 icon_ = *image;
723 else
724 icon_ = SkBitmap();
725 if (icon_.empty()) {
726 // Let's set default icon bitmap whose size is equal to the default icon's
727 // pixel size under maximal supported scale factor. If the bitmap is larger
728 // than the one we need, it will be scaled down by the ui code.
729 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
733 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
734 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
735 ShowConfirmation();
738 void ExtensionInstallPrompt::LoadImageIfNeeded() {
739 // Bundle install prompts do not have an icon.
740 // Also |install_ui_.profile()| can be NULL in unit tests.
741 if (!icon_.empty() || !install_ui_->profile()) {
742 ShowConfirmation();
743 return;
746 // Load the image asynchronously. For the response, check OnImageLoaded.
747 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
748 extension_,
749 extension_misc::EXTENSION_ICON_LARGE,
750 ExtensionIconSet::MATCH_BIGGER);
751 // Load the icon whose pixel size is large enough to be displayed under
752 // maximal supported scale factor. UI code will scale the icon down if needed.
753 // TODO(tbarzic): We should use IconImage here and load the required bitmap
754 // lazily.
755 int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
756 extensions::ImageLoader::Get(install_ui_->profile())->LoadImageAsync(
757 extension_, image, gfx::Size(pixel_size, pixel_size),
758 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
761 void ExtensionInstallPrompt::OnGetTokenSuccess(
762 const OAuth2TokenService::Request* request,
763 const std::string& access_token,
764 const base::Time& expiration_time) {
765 DCHECK_EQ(login_token_request_.get(), request);
766 login_token_request_.reset();
768 const extensions::OAuth2Info& oauth2_info =
769 extensions::OAuth2Info::GetOAuth2Info(extension_);
771 token_flow_.reset(new OAuth2MintTokenFlow(
772 install_ui_->profile()->GetRequestContext(),
773 this,
774 OAuth2MintTokenFlow::Parameters(
775 access_token,
776 extension_->id(),
777 oauth2_info.client_id,
778 oauth2_info.scopes,
779 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE)));
780 token_flow_->Start();
783 void ExtensionInstallPrompt::OnGetTokenFailure(
784 const OAuth2TokenService::Request* request,
785 const GoogleServiceAuthError& error) {
786 DCHECK_EQ(login_token_request_.get(), request);
787 login_token_request_.reset();
788 ShowConfirmation();
791 void ExtensionInstallPrompt::OnIssueAdviceSuccess(
792 const IssueAdviceInfo& advice_info) {
793 prompt_.SetOAuthIssueAdvice(advice_info);
794 record_oauth2_grant_ = true;
795 ShowConfirmation();
798 void ExtensionInstallPrompt::OnMintTokenFailure(
799 const GoogleServiceAuthError& error) {
800 ShowConfirmation();
803 void ExtensionInstallPrompt::ShowConfirmation() {
804 if (prompt_.type() == INSTALL_PROMPT)
805 prompt_.set_experiment(ExtensionInstallPromptExperiment::Find());
806 else
807 prompt_.set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
809 if (permissions_.get() &&
810 (!extension_ ||
811 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
812 extension_))) {
813 Manifest::Type extension_type = extension_ ?
814 extension_->GetType() : Manifest::TYPE_UNKNOWN;
815 prompt_.SetPermissions(
816 extensions::PermissionMessageProvider::Get()->
817 GetWarningMessages(permissions_, extension_type));
818 prompt_.SetPermissionsDetails(
819 extensions::PermissionMessageProvider::Get()->
820 GetWarningMessagesDetails(permissions_, extension_type));
823 switch (prompt_.type()) {
824 case PERMISSIONS_PROMPT:
825 case RE_ENABLE_PROMPT:
826 case INLINE_INSTALL_PROMPT:
827 case EXTERNAL_INSTALL_PROMPT:
828 case INSTALL_PROMPT:
829 case LAUNCH_PROMPT:
830 case POST_INSTALL_PERMISSIONS_PROMPT: {
831 prompt_.set_extension(extension_);
832 prompt_.set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
833 break;
835 case BUNDLE_INSTALL_PROMPT: {
836 prompt_.set_bundle(bundle_);
837 break;
839 default:
840 NOTREACHED() << "Unknown message";
841 return;
844 if (AutoConfirmPrompt(delegate_))
845 return;
847 if (show_dialog_callback_.is_null())
848 GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
849 else
850 show_dialog_callback_.Run(show_params_, delegate_, prompt_);