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),
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
) {
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(
224 bool is_showing_details
) {
226 case PERMISSIONS_DETAILS
:
227 is_showing_details_for_permissions_
[index
] = is_showing_details
;
230 is_showing_details_for_oauth_
[index
] = is_showing_details
;
232 case RETAINED_FILES_DETAILS
:
233 is_showing_details_for_retained_files_
= is_showing_details
;
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.
250 oauth_user_name_
= base::UTF8ToUTF16(profile
->GetPrefs()->GetString(
251 prefs::kGoogleServicesUsername
));
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
,
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
;
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
;
300 resource_id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION
;
301 return l10n_util::GetStringUTF16(resource_id
);
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)
326 if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
)
327 return ShouldDisplayRevokeFilesButton();
332 base::string16
ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
333 if (type_
== EXTERNAL_INSTALL_PROMPT
) {
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
;
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())
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 {
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) {
400 if (rating_fractional
< 0.33 || rating_fractional
> 0.66) {
401 rating_fractional
= 0;
404 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
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
);
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
)
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 {
457 case PERMISSIONS_DETAILS
:
458 CHECK_LT(index
, is_showing_details_for_permissions_
.size());
459 return is_showing_details_for_permissions_
[index
];
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_
;
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
)
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
) {
508 scoped_refptr
<Extension
>
509 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
510 const base::DictionaryValue
* manifest
,
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
,
523 if (!localized_description
.empty()) {
524 localized_manifest
->SetString(extensions::manifest_keys::kDescription
,
525 localized_description
);
529 return Extension::Create(
532 localized_manifest
.get() ? *localized_manifest
.get() : *manifest
,
538 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents
* contents
)
539 : OAuth2TokenService::Consumer("extensions_install"),
540 record_oauth2_grant_(false),
541 ui_loop_(base::MessageLoop::current()),
544 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents
))),
545 show_params_(contents
),
547 prompt_(UNSET_PROMPT_TYPE
) {
548 prompt_
.SetUserNameFromProfile(install_ui_
->profile());
551 ExtensionInstallPrompt::ExtensionInstallPrompt(
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()),
560 install_ui_(ExtensionInstallUI::Create(profile
)),
561 show_params_(native_window
, navigator
),
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());
575 permissions_
= permissions
;
577 prompt_
.set_type(BUNDLE_INSTALL_PROMPT
);
582 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
584 const Extension
* extension
,
586 const ExtensionInstallPrompt::Prompt
& prompt
) {
587 DCHECK(ui_loop_
== base::MessageLoop::current());
588 extension_
= extension
;
589 permissions_
= extension
->GetActivePermissions();
590 delegate_
= delegate
;
597 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
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
604 extension_
= extension
;
606 ConfirmInstall(delegate
, extension
, show_dialog_callback
);
609 void ExtensionInstallPrompt::ConfirmInstall(
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();
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
:
650 void ExtensionInstallPrompt::ConfirmExternalInstall(
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
;
660 show_dialog_callback_
= show_dialog_callback
;
665 void ExtensionInstallPrompt::ConfirmPermissions(
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
);
678 void ExtensionInstallPrompt::ConfirmIssueAdvice(
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
);
693 void ExtensionInstallPrompt::ReviewPermissions(
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
);
707 void ExtensionInstallPrompt::OnInstallSuccess(const Extension
* extension
,
709 extension_
= extension
;
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
) {
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());
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()) {
746 // Load the image asynchronously. For the response, check OnImageLoaded.
747 extensions::ExtensionResource image
= extensions::IconsInfo::GetIconResource(
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
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(),
774 OAuth2MintTokenFlow::Parameters(
777 oauth2_info
.client_id
,
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();
791 void ExtensionInstallPrompt::OnIssueAdviceSuccess(
792 const IssueAdviceInfo
& advice_info
) {
793 prompt_
.SetOAuthIssueAdvice(advice_info
);
794 record_oauth2_grant_
= true;
798 void ExtensionInstallPrompt::OnMintTokenFailure(
799 const GoogleServiceAuthError
& error
) {
803 void ExtensionInstallPrompt::ShowConfirmation() {
804 if (prompt_
.type() == INSTALL_PROMPT
)
805 prompt_
.set_experiment(ExtensionInstallPromptExperiment::Find());
807 prompt_
.set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
809 if (permissions_
.get() &&
811 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
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
:
830 case POST_INSTALL_PERMISSIONS_PROMPT
: {
831 prompt_
.set_extension(extension_
);
832 prompt_
.set_icon(gfx::Image::CreateFrom1xBitmap(icon_
));
835 case BUNDLE_INSTALL_PROMPT
: {
836 prompt_
.set_bundle(bundle_
);
840 NOTREACHED() << "Unknown message";
844 if (AutoConfirmPrompt(delegate_
))
847 if (show_dialog_callback_
.is_null())
848 GetDefaultShowDialogCallback().Run(show_params_
, delegate_
, prompt_
);
850 show_dialog_callback_
.Run(show_params_
, delegate_
, prompt_
);