Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_install_prompt.cc
blob6e94baa0e37dd266d1c29a016048ad7d77914932
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) {
204 ExtensionInstallPrompt::Prompt::~Prompt() {
207 void ExtensionInstallPrompt::Prompt::SetPermissions(
208 const std::vector<base::string16>& permissions) {
209 permissions_ = permissions;
212 void ExtensionInstallPrompt::Prompt::SetPermissionsDetails(
213 const std::vector<base::string16>& details) {
214 details_ = details;
215 is_showing_details_for_permissions_.clear();
216 for (size_t i = 0; i < details.size(); ++i)
217 is_showing_details_for_permissions_.push_back(false);
220 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
221 DetailsType type,
222 size_t index,
223 bool is_showing_details) {
224 switch (type) {
225 case PERMISSIONS_DETAILS:
226 is_showing_details_for_permissions_[index] = is_showing_details;
227 break;
228 case OAUTH_DETAILS:
229 is_showing_details_for_oauth_[index] = is_showing_details;
230 break;
231 case RETAINED_FILES_DETAILS:
232 is_showing_details_for_retained_files_ = is_showing_details;
233 break;
237 void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice(
238 const IssueAdviceInfo& issue_advice) {
239 is_showing_details_for_oauth_.clear();
240 for (size_t i = 0; i < issue_advice.size(); ++i)
241 is_showing_details_for_oauth_.push_back(false);
243 oauth_issue_advice_ = issue_advice;
246 void ExtensionInstallPrompt::Prompt::SetUserNameFromProfile(Profile* profile) {
247 // |profile| can be NULL in unit tests.
248 if (profile) {
249 oauth_user_name_ = base::UTF8ToUTF16(profile->GetPrefs()->GetString(
250 prefs::kGoogleServicesUsername));
251 } else {
252 oauth_user_name_.clear();
256 void ExtensionInstallPrompt::Prompt::SetInlineInstallWebstoreData(
257 const std::string& localized_user_count,
258 bool show_user_count,
259 double average_rating,
260 int rating_count) {
261 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
262 localized_user_count_ = localized_user_count;
263 show_user_count_ = show_user_count;
264 average_rating_ = average_rating;
265 rating_count_ = rating_count;
268 base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
269 int resource_id = kTitleIds[type_];
271 if (type_ == INSTALL_PROMPT) {
272 if (extension_->is_app())
273 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
274 else if (extension_->is_theme())
275 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
276 else
277 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
278 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
279 return l10n_util::GetStringFUTF16(
280 resource_id, base::UTF8ToUTF16(extension_->name()));
283 return l10n_util::GetStringUTF16(resource_id);
286 base::string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
287 if (type_ == INLINE_INSTALL_PROMPT) {
288 return base::UTF8ToUTF16(extension_->name());
289 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
290 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
291 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
292 int resource_id = -1;
293 if (extension_->is_app())
294 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
295 else if (extension_->is_theme())
296 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
297 else
298 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
299 return l10n_util::GetStringUTF16(resource_id);
300 } else {
301 return l10n_util::GetStringFUTF16(
302 kHeadingIds[type_], base::UTF8ToUTF16(extension_->name()));
306 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
307 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT &&
308 ShouldDisplayRevokeFilesButton()) {
309 return kButtons[type_] | ui::DIALOG_BUTTON_OK;
312 return kButtons[type_];
315 bool ExtensionInstallPrompt::Prompt::ShouldShowExplanationText() const {
316 return type_ == INSTALL_PROMPT &&
317 extension_->is_extension() && experiment_ && experiment_->text_only();
320 bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
321 if (kAcceptButtonIds[type_] == 0)
322 return false;
324 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT)
325 return ShouldDisplayRevokeFilesButton();
327 return true;
330 base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
331 if (type_ == EXTERNAL_INSTALL_PROMPT) {
332 int id = -1;
333 if (extension_->is_app())
334 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
335 else if (extension_->is_theme())
336 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
337 else
338 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
339 return l10n_util::GetStringUTF16(id);
341 if (ShouldShowExplanationText())
342 return experiment_->GetOkButtonText();
343 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
346 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
347 if (ShouldShowExplanationText())
348 return true;
349 return kAbortButtonIds[type_] > 0;
352 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
353 CHECK(HasAbortButtonLabel());
354 if (ShouldShowExplanationText())
355 return experiment_->GetCancelButtonText();
356 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
359 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
360 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
363 base::string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
364 return l10n_util::GetStringFUTF16(kOAuthHeaderIds[type_], oauth_user_name_);
367 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
368 const int kRetainedFilesMessageIDs[6] = {
369 IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT,
370 IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR,
371 IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO,
372 IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO,
373 IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW,
374 IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY,
376 std::vector<int> message_ids;
377 for (size_t i = 0; i < arraysize(kRetainedFilesMessageIDs); i++) {
378 message_ids.push_back(kRetainedFilesMessageIDs[i]);
380 return l10n_util::GetPluralStringFUTF16(message_ids, GetRetainedFileCount());
383 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
384 return GetPermissionCount() > 0 || type_ == POST_INSTALL_PERMISSIONS_PROMPT;
387 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
388 StarAppender appender, void* data) const {
389 CHECK(appender);
390 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
391 int rating_integer = floor(average_rating_);
392 double rating_fractional = average_rating_ - rating_integer;
394 if (rating_fractional > 0.66) {
395 rating_integer++;
398 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
399 rating_fractional = 0;
402 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
403 int i;
404 for (i = 0; i < rating_integer; i++) {
405 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
407 if (rating_fractional) {
408 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
409 i++;
411 for (; i < kMaxExtensionRating; i++) {
412 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
416 base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
417 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
418 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
419 base::IntToString16(rating_count_));
422 base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
423 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
425 if (show_user_count_) {
426 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
427 base::UTF8ToUTF16(localized_user_count_));
429 return base::string16();
432 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
433 return permissions_.size();
436 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount() const {
437 return details_.size();
440 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index)
441 const {
442 CHECK_LT(index, permissions_.size());
443 return permissions_[index];
446 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
447 size_t index) const {
448 CHECK_LT(index, details_.size());
449 return details_[index];
452 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
453 DetailsType type, size_t index) const {
454 switch (type) {
455 case PERMISSIONS_DETAILS:
456 CHECK_LT(index, is_showing_details_for_permissions_.size());
457 return is_showing_details_for_permissions_[index];
458 case OAUTH_DETAILS:
459 CHECK_LT(index, is_showing_details_for_oauth_.size());
460 return is_showing_details_for_oauth_[index];
461 case RETAINED_FILES_DETAILS:
462 return is_showing_details_for_retained_files_;
464 return false;
467 size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
468 return oauth_issue_advice_.size();
471 const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue(
472 size_t index) const {
473 CHECK_LT(index, oauth_issue_advice_.size());
474 return oauth_issue_advice_[index];
477 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
478 return retained_files_.size();
481 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
482 const {
483 CHECK_LT(index, retained_files_.size());
484 return retained_files_[index].AsUTF16Unsafe();
487 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
488 return !retained_files_.empty();
491 ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
492 : parent_web_contents(contents),
493 parent_window(NativeWindowForWebContents(contents)),
494 navigator(contents) {
497 ExtensionInstallPrompt::ShowParams::ShowParams(
498 gfx::NativeWindow window,
499 content::PageNavigator* navigator)
500 : parent_web_contents(NULL),
501 parent_window(window),
502 navigator(navigator) {
505 // static
506 scoped_refptr<Extension>
507 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
508 const base::DictionaryValue* manifest,
509 int flags,
510 const std::string& id,
511 const std::string& localized_name,
512 const std::string& localized_description,
513 std::string* error) {
514 scoped_ptr<base::DictionaryValue> localized_manifest;
515 if (!localized_name.empty() || !localized_description.empty()) {
516 localized_manifest.reset(manifest->DeepCopy());
517 if (!localized_name.empty()) {
518 localized_manifest->SetString(extensions::manifest_keys::kName,
519 localized_name);
521 if (!localized_description.empty()) {
522 localized_manifest->SetString(extensions::manifest_keys::kDescription,
523 localized_description);
527 return Extension::Create(
528 base::FilePath(),
529 Manifest::INTERNAL,
530 localized_manifest.get() ? *localized_manifest.get() : *manifest,
531 flags,
533 error);
536 ExtensionInstallPrompt::ExtensionInstallPrompt(
537 content::WebContents* contents)
538 : OAuth2TokenService::Consumer("extensions_install"),
539 record_oauth2_grant_(false),
540 ui_loop_(base::MessageLoop::current()),
541 extension_(NULL),
542 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))),
543 show_params_(contents),
544 delegate_(NULL),
545 prompt_(UNSET_PROMPT_TYPE) {
546 prompt_.SetUserNameFromProfile(install_ui_->profile());
549 ExtensionInstallPrompt::ExtensionInstallPrompt(
550 Profile* profile,
551 gfx::NativeWindow native_window,
552 content::PageNavigator* navigator)
553 : OAuth2TokenService::Consumer("extensions_install"),
554 record_oauth2_grant_(false),
555 ui_loop_(base::MessageLoop::current()),
556 extension_(NULL),
557 install_ui_(ExtensionInstallUI::Create(profile)),
558 show_params_(native_window, navigator),
559 delegate_(NULL),
560 prompt_(UNSET_PROMPT_TYPE) {
561 prompt_.SetUserNameFromProfile(install_ui_->profile());
564 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
567 void ExtensionInstallPrompt::ConfirmBundleInstall(
568 extensions::BundleInstaller* bundle,
569 const PermissionSet* permissions) {
570 DCHECK(ui_loop_ == base::MessageLoop::current());
571 bundle_ = bundle;
572 permissions_ = permissions;
573 delegate_ = bundle;
574 prompt_.set_type(BUNDLE_INSTALL_PROMPT);
576 ShowConfirmation();
579 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
580 Delegate* delegate,
581 const Extension* extension,
582 SkBitmap* icon,
583 const ExtensionInstallPrompt::Prompt& prompt) {
584 DCHECK(ui_loop_ == base::MessageLoop::current());
585 extension_ = extension;
586 permissions_ = extension->GetActivePermissions();
587 delegate_ = delegate;
588 prompt_ = prompt;
590 SetIcon(icon);
591 ShowConfirmation();
594 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
595 Delegate* delegate,
596 const Extension* extension,
597 const SkBitmap* icon,
598 const ShowDialogCallback& show_dialog_callback) {
599 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
600 // remaining fields.
601 extension_ = extension;
602 SetIcon(icon);
603 ConfirmInstall(delegate, extension, show_dialog_callback);
606 void ExtensionInstallPrompt::ConfirmInstall(
607 Delegate* delegate,
608 const Extension* extension,
609 const ShowDialogCallback& show_dialog_callback) {
610 DCHECK(ui_loop_ == base::MessageLoop::current());
611 extension_ = extension;
612 permissions_ = extension->GetActivePermissions();
613 delegate_ = delegate;
614 prompt_.set_type(INSTALL_PROMPT);
615 show_dialog_callback_ = show_dialog_callback;
617 // We special-case themes to not show any confirm UI. Instead they are
618 // immediately installed, and then we show an infobar (see OnInstallSuccess)
619 // to allow the user to revert if they don't like it.
621 // We don't do this in the case where off-store extension installs are
622 // disabled because in that case, we don't show the dangerous download UI, so
623 // we need the UI confirmation.
624 if (extension->is_theme()) {
625 if (extension->from_webstore() ||
626 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
627 delegate->InstallUIProceed();
628 return;
632 LoadImageIfNeeded();
635 void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
636 const Extension* extension) {
637 DCHECK(ui_loop_ == base::MessageLoop::current());
638 extension_ = extension;
639 permissions_ = extension->GetActivePermissions();
640 delegate_ = delegate;
641 prompt_.set_type(extension->is_ephemeral() ? LAUNCH_PROMPT :
642 RE_ENABLE_PROMPT);
644 LoadImageIfNeeded();
647 void ExtensionInstallPrompt::ConfirmExternalInstall(
648 Delegate* delegate,
649 const Extension* extension,
650 const ShowDialogCallback& show_dialog_callback) {
651 DCHECK(ui_loop_ == base::MessageLoop::current());
652 extension_ = extension;
653 permissions_ = extension->GetActivePermissions();
654 delegate_ = delegate;
655 prompt_.set_type(EXTERNAL_INSTALL_PROMPT);
656 show_dialog_callback_ = show_dialog_callback;
658 LoadImageIfNeeded();
661 void ExtensionInstallPrompt::ConfirmPermissions(
662 Delegate* delegate,
663 const Extension* extension,
664 const PermissionSet* permissions) {
665 DCHECK(ui_loop_ == base::MessageLoop::current());
666 extension_ = extension;
667 permissions_ = permissions;
668 delegate_ = delegate;
669 prompt_.set_type(PERMISSIONS_PROMPT);
671 LoadImageIfNeeded();
674 void ExtensionInstallPrompt::ConfirmIssueAdvice(
675 Delegate* delegate,
676 const Extension* extension,
677 const IssueAdviceInfo& issue_advice) {
678 DCHECK(ui_loop_ == base::MessageLoop::current());
679 extension_ = extension;
680 delegate_ = delegate;
681 prompt_.set_type(PERMISSIONS_PROMPT);
683 record_oauth2_grant_ = true;
684 prompt_.SetOAuthIssueAdvice(issue_advice);
686 LoadImageIfNeeded();
689 void ExtensionInstallPrompt::ReviewPermissions(
690 Delegate* delegate,
691 const Extension* extension,
692 const std::vector<base::FilePath>& retained_file_paths) {
693 DCHECK(ui_loop_ == base::MessageLoop::current());
694 extension_ = extension;
695 permissions_ = extension->GetActivePermissions();
696 prompt_.set_retained_files(retained_file_paths);
697 delegate_ = delegate;
698 prompt_.set_type(POST_INSTALL_PERMISSIONS_PROMPT);
700 LoadImageIfNeeded();
703 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
704 SkBitmap* icon) {
705 extension_ = extension;
706 SetIcon(icon);
708 install_ui_->OnInstallSuccess(extension, &icon_);
711 void ExtensionInstallPrompt::OnInstallFailure(
712 const extensions::CrxInstallerError& error) {
713 install_ui_->OnInstallFailure(error);
716 void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
717 if (image)
718 icon_ = *image;
719 else
720 icon_ = SkBitmap();
721 if (icon_.empty()) {
722 // Let's set default icon bitmap whose size is equal to the default icon's
723 // pixel size under maximal supported scale factor. If the bitmap is larger
724 // than the one we need, it will be scaled down by the ui code.
725 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
729 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
730 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
731 ShowConfirmation();
734 void ExtensionInstallPrompt::LoadImageIfNeeded() {
735 // Bundle install prompts do not have an icon.
736 // Also |install_ui_.profile()| can be NULL in unit tests.
737 if (!icon_.empty() || !install_ui_->profile()) {
738 ShowConfirmation();
739 return;
742 // Load the image asynchronously. For the response, check OnImageLoaded.
743 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
744 extension_,
745 extension_misc::EXTENSION_ICON_LARGE,
746 ExtensionIconSet::MATCH_BIGGER);
747 // Load the icon whose pixel size is large enough to be displayed under
748 // maximal supported scale factor. UI code will scale the icon down if needed.
749 // TODO(tbarzic): We should use IconImage here and load the required bitmap
750 // lazily.
751 int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
752 extensions::ImageLoader::Get(install_ui_->profile())->LoadImageAsync(
753 extension_, image, gfx::Size(pixel_size, pixel_size),
754 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
757 void ExtensionInstallPrompt::OnGetTokenSuccess(
758 const OAuth2TokenService::Request* request,
759 const std::string& access_token,
760 const base::Time& expiration_time) {
761 DCHECK_EQ(login_token_request_.get(), request);
762 login_token_request_.reset();
764 const extensions::OAuth2Info& oauth2_info =
765 extensions::OAuth2Info::GetOAuth2Info(extension_);
767 token_flow_.reset(new OAuth2MintTokenFlow(
768 install_ui_->profile()->GetRequestContext(),
769 this,
770 OAuth2MintTokenFlow::Parameters(
771 access_token,
772 extension_->id(),
773 oauth2_info.client_id,
774 oauth2_info.scopes,
775 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE)));
776 token_flow_->Start();
779 void ExtensionInstallPrompt::OnGetTokenFailure(
780 const OAuth2TokenService::Request* request,
781 const GoogleServiceAuthError& error) {
782 DCHECK_EQ(login_token_request_.get(), request);
783 login_token_request_.reset();
784 ShowConfirmation();
787 void ExtensionInstallPrompt::OnIssueAdviceSuccess(
788 const IssueAdviceInfo& advice_info) {
789 prompt_.SetOAuthIssueAdvice(advice_info);
790 record_oauth2_grant_ = true;
791 ShowConfirmation();
794 void ExtensionInstallPrompt::OnMintTokenFailure(
795 const GoogleServiceAuthError& error) {
796 ShowConfirmation();
799 void ExtensionInstallPrompt::ShowConfirmation() {
800 if (prompt_.type() == INSTALL_PROMPT)
801 prompt_.set_experiment(ExtensionInstallPromptExperiment::Find());
802 else
803 prompt_.set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
805 if (permissions_.get() &&
806 (!extension_ ||
807 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
808 extension_))) {
809 Manifest::Type extension_type = extension_ ?
810 extension_->GetType() : Manifest::TYPE_UNKNOWN;
811 prompt_.SetPermissions(
812 extensions::PermissionMessageProvider::Get()->
813 GetWarningMessages(permissions_, extension_type));
814 prompt_.SetPermissionsDetails(
815 extensions::PermissionMessageProvider::Get()->
816 GetWarningMessagesDetails(permissions_, extension_type));
819 switch (prompt_.type()) {
820 case PERMISSIONS_PROMPT:
821 case RE_ENABLE_PROMPT:
822 case INLINE_INSTALL_PROMPT:
823 case EXTERNAL_INSTALL_PROMPT:
824 case INSTALL_PROMPT:
825 case LAUNCH_PROMPT:
826 case POST_INSTALL_PERMISSIONS_PROMPT: {
827 prompt_.set_extension(extension_);
828 prompt_.set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
829 break;
831 case BUNDLE_INSTALL_PROMPT: {
832 prompt_.set_bundle(bundle_);
833 break;
835 default:
836 NOTREACHED() << "Unknown message";
837 return;
840 if (AutoConfirmPrompt(delegate_))
841 return;
843 if (show_dialog_callback_.is_null())
844 GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
845 else
846 show_dialog_callback_.Run(show_params_, delegate_, prompt_);