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"
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
;
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
,
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
))
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(
161 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed
,
162 base::Unretained(delegate
)));
166 if (value
== "cancel") {
167 base::MessageLoop::current()->PostTask(
169 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort
,
170 base::Unretained(delegate
),
179 Profile
* ProfileForWebContents(content::WebContents
* web_contents
) {
182 return Profile::FromBrowserContext(web_contents
->GetBrowserContext());
185 gfx::NativeWindow
NativeWindowForWebContents(content::WebContents
* contents
) {
189 return contents
->GetView()->GetTopLevelNativeWindow();
194 ExtensionInstallPrompt::Prompt::Prompt(PromptType type
)
196 is_showing_details_for_retained_files_(false),
199 average_rating_(0.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
) {
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(
223 bool is_showing_details
) {
225 case PERMISSIONS_DETAILS
:
226 is_showing_details_for_permissions_
[index
] = is_showing_details
;
229 is_showing_details_for_oauth_
[index
] = is_showing_details
;
231 case RETAINED_FILES_DETAILS
:
232 is_showing_details_for_retained_files_
= is_showing_details
;
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.
249 oauth_user_name_
= base::UTF8ToUTF16(profile
->GetPrefs()->GetString(
250 prefs::kGoogleServicesUsername
));
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
,
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
;
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
;
298 resource_id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION
;
299 return l10n_util::GetStringUTF16(resource_id
);
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)
324 if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
)
325 return ShouldDisplayRevokeFilesButton();
330 base::string16
ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
331 if (type_
== EXTERNAL_INSTALL_PROMPT
) {
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
;
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())
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 {
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) {
398 if (rating_fractional
< 0.33 || rating_fractional
> 0.66) {
399 rating_fractional
= 0;
402 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
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
);
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
)
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 {
455 case PERMISSIONS_DETAILS
:
456 CHECK_LT(index
, is_showing_details_for_permissions_
.size());
457 return is_showing_details_for_permissions_
[index
];
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_
;
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
)
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
) {
506 scoped_refptr
<Extension
>
507 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
508 const base::DictionaryValue
* manifest
,
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
,
521 if (!localized_description
.empty()) {
522 localized_manifest
->SetString(extensions::manifest_keys::kDescription
,
523 localized_description
);
527 return Extension::Create(
530 localized_manifest
.get() ? *localized_manifest
.get() : *manifest
,
536 ExtensionInstallPrompt::ExtensionInstallPrompt(
537 content::WebContents
* contents
)
538 : OAuth2TokenService::Consumer("extensions_install"),
539 record_oauth2_grant_(false),
540 ui_loop_(base::MessageLoop::current()),
542 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents
))),
543 show_params_(contents
),
545 prompt_(UNSET_PROMPT_TYPE
) {
546 prompt_
.SetUserNameFromProfile(install_ui_
->profile());
549 ExtensionInstallPrompt::ExtensionInstallPrompt(
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()),
557 install_ui_(ExtensionInstallUI::Create(profile
)),
558 show_params_(native_window
, navigator
),
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());
572 permissions_
= permissions
;
574 prompt_
.set_type(BUNDLE_INSTALL_PROMPT
);
579 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
581 const Extension
* extension
,
583 const ExtensionInstallPrompt::Prompt
& prompt
) {
584 DCHECK(ui_loop_
== base::MessageLoop::current());
585 extension_
= extension
;
586 permissions_
= extension
->GetActivePermissions();
587 delegate_
= delegate
;
594 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
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
601 extension_
= extension
;
603 ConfirmInstall(delegate
, extension
, show_dialog_callback
);
606 void ExtensionInstallPrompt::ConfirmInstall(
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();
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
:
647 void ExtensionInstallPrompt::ConfirmExternalInstall(
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
;
661 void ExtensionInstallPrompt::ConfirmPermissions(
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
);
674 void ExtensionInstallPrompt::ConfirmIssueAdvice(
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
);
689 void ExtensionInstallPrompt::ReviewPermissions(
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
);
703 void ExtensionInstallPrompt::OnInstallSuccess(const Extension
* extension
,
705 extension_
= extension
;
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
) {
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());
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()) {
742 // Load the image asynchronously. For the response, check OnImageLoaded.
743 extensions::ExtensionResource image
= extensions::IconsInfo::GetIconResource(
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
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(),
770 OAuth2MintTokenFlow::Parameters(
773 oauth2_info
.client_id
,
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();
787 void ExtensionInstallPrompt::OnIssueAdviceSuccess(
788 const IssueAdviceInfo
& advice_info
) {
789 prompt_
.SetOAuthIssueAdvice(advice_info
);
790 record_oauth2_grant_
= true;
794 void ExtensionInstallPrompt::OnMintTokenFailure(
795 const GoogleServiceAuthError
& error
) {
799 void ExtensionInstallPrompt::ShowConfirmation() {
800 if (prompt_
.type() == INSTALL_PROMPT
)
801 prompt_
.set_experiment(ExtensionInstallPromptExperiment::Find());
803 prompt_
.set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
805 if (permissions_
.get() &&
807 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
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
:
826 case POST_INSTALL_PERMISSIONS_PROMPT
: {
827 prompt_
.set_extension(extension_
);
828 prompt_
.set_icon(gfx::Image::CreateFrom1xBitmap(icon_
));
831 case BUNDLE_INSTALL_PROMPT
: {
832 prompt_
.set_bundle(bundle_
);
836 NOTREACHED() << "Unknown message";
840 if (AutoConfirmPrompt(delegate_
))
843 if (show_dialog_callback_
.is_null())
844 GetDefaultShowDialogCallback().Run(show_params_
, delegate_
, prompt_
);
846 show_dialog_callback_
.Run(show_params_
, delegate_
, prompt_
);