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_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/extensions/bundle_installer.h"
18 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
19 #include "chrome/browser/extensions/extension_util.h"
20 #include "chrome/browser/extensions/permissions_updater.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/extensions/extension_install_ui_factory.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/grit/chromium_strings.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "content/public/browser/web_contents.h"
27 #include "extensions/browser/extension_prefs.h"
28 #include "extensions/browser/extension_util.h"
29 #include "extensions/browser/image_loader.h"
30 #include "extensions/browser/install/extension_install_ui.h"
31 #include "extensions/common/constants.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/extension_icon_set.h"
34 #include "extensions/common/extension_resource.h"
35 #include "extensions/common/feature_switch.h"
36 #include "extensions/common/manifest.h"
37 #include "extensions/common/manifest_constants.h"
38 #include "extensions/common/manifest_handlers/icons_handler.h"
39 #include "extensions/common/manifest_handlers/permissions_parser.h"
40 #include "extensions/common/permissions/permission_message_provider.h"
41 #include "extensions/common/permissions/permission_set.h"
42 #include "extensions/common/permissions/permissions_data.h"
43 #include "extensions/common/url_pattern.h"
44 #include "grit/theme_resources.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h"
47 #include "ui/base/ui_base_types.h"
48 #include "ui/gfx/image/image.h"
50 using extensions::BundleInstaller
;
51 using extensions::Extension
;
52 using extensions::Manifest
;
53 using extensions::PermissionSet
;
57 bool AllowWebstoreData(ExtensionInstallPrompt::PromptType type
) {
58 return type
== ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
||
59 type
== ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT
||
60 type
== ExtensionInstallPrompt::REPAIR_PROMPT
;
63 static const int kTitleIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
64 0, // The regular install prompt depends on what's being installed.
65 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE
,
66 IDS_EXTENSION_INSTALL_PROMPT_TITLE
,
67 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE
,
68 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE
,
69 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE
,
70 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE
,
71 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE
,
72 0, // The remote install prompt depends on what's being installed.
73 0, // The repair install prompt depends on what's being installed.
74 0, // The delegated install prompt depends on what's being installed.
76 static const int kHeadingIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
77 IDS_EXTENSION_INSTALL_PROMPT_HEADING
,
78 0, // Inline installs use the extension name.
79 0, // Heading for bundle installs depends on the bundle contents.
80 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING
,
81 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING
,
82 0, // External installs use different strings for extensions/apps.
83 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING
,
84 IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING
,
85 IDS_EXTENSION_REMOTE_INSTALL_PROMPT_HEADING
,
86 IDS_EXTENSION_REPAIR_PROMPT_HEADING
,
87 IDS_EXTENSION_INSTALL_PROMPT_HEADING
,
89 static const int kButtons
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
90 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
91 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
92 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
93 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
94 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
95 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
96 ui::DIALOG_BUTTON_CANCEL
,
97 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
98 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
99 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
100 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
102 static const int kAcceptButtonIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
103 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
104 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
105 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
106 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON
,
107 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON
,
108 0, // External installs use different strings for extensions/apps.
109 0, // Different strings depending on the files and devices retained.
110 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON
,
111 IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON
,
112 IDS_EXTENSION_PROMPT_REPAIR_BUTTON
,
113 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON
,
115 static const int kAbortButtonIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
116 0, // These all use the platform's default cancel label.
120 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON
,
121 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON
,
123 0, // Platform dependent cancel button.
126 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON
,
129 kPermissionsHeaderIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
130 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
131 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
132 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO
,
133 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO
,
134 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO
,
135 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
136 IDS_EXTENSION_PROMPT_CAN_ACCESS
,
137 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
138 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
139 IDS_EXTENSION_PROMPT_CAN_ACCESS
,
140 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
143 // Returns bitmap for the default icon with size equal to the default icon's
144 // pixel size under maximal supported scale factor.
145 SkBitmap
GetDefaultIconBitmapForMaxScaleFactor(bool is_app
) {
146 const gfx::ImageSkia
& image
= is_app
?
147 extensions::util::GetDefaultAppIcon() :
148 extensions::util::GetDefaultExtensionIcon();
149 return image
.GetRepresentation(
150 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
153 // If auto confirm is enabled then posts a task to proceed with or cancel the
154 // install and returns true. Otherwise returns false.
155 bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate
* delegate
) {
156 switch (ExtensionInstallPrompt::g_auto_confirm_for_tests
) {
157 case ExtensionInstallPrompt::NONE
:
159 // We use PostTask instead of calling the delegate directly here, because in
160 // the real implementations it's highly likely the message loop will be
161 // pumping a few times before the user clicks accept or cancel.
162 case ExtensionInstallPrompt::ACCEPT
:
163 base::MessageLoop::current()->PostTask(
165 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed
,
166 base::Unretained(delegate
)));
168 case ExtensionInstallPrompt::CANCEL
:
169 base::MessageLoop::current()->PostTask(
171 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort
,
172 base::Unretained(delegate
),
181 Profile
* ProfileForWebContents(content::WebContents
* web_contents
) {
184 return Profile::FromBrowserContext(web_contents
->GetBrowserContext());
189 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
190 InstallPromptPermissions() {
192 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
193 ~InstallPromptPermissions() {
197 ExtensionInstallPrompt::AutoConfirmForTests
198 ExtensionInstallPrompt::g_auto_confirm_for_tests
= ExtensionInstallPrompt::NONE
;
200 ExtensionInstallPrompt::PromptType
201 ExtensionInstallPrompt::g_last_prompt_type_for_tests
=
202 ExtensionInstallPrompt::UNSET_PROMPT_TYPE
;
204 // This should match the PromptType enum.
205 std::string
ExtensionInstallPrompt::PromptTypeToString(PromptType type
) {
207 case ExtensionInstallPrompt::INSTALL_PROMPT
:
208 return "INSTALL_PROMPT";
209 case ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
:
210 return "INLINE_INSTALL_PROMPT";
211 case ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT
:
212 return "BUNDLE_INSTALL_PROMPT";
213 case ExtensionInstallPrompt::RE_ENABLE_PROMPT
:
214 return "RE_ENABLE_PROMPT";
215 case ExtensionInstallPrompt::PERMISSIONS_PROMPT
:
216 return "PERMISSIONS_PROMPT";
217 case ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT
:
218 return "EXTERNAL_INSTALL_PROMPT";
219 case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT
:
220 return "POST_INSTALL_PERMISSIONS_PROMPT";
221 case ExtensionInstallPrompt::LAUNCH_PROMPT
:
222 return "LAUNCH_PROMPT";
223 case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT
:
224 return "REMOTE_INSTALL_PROMPT";
225 case ExtensionInstallPrompt::REPAIR_PROMPT
:
226 return "REPAIR_PROMPT";
227 case ExtensionInstallPrompt::DELEGATED_PERMISSIONS_PROMPT
:
228 return "DELEGATED_PERMISSIONS_PROMPT";
229 case ExtensionInstallPrompt::UNSET_PROMPT_TYPE
:
230 case ExtensionInstallPrompt::NUM_PROMPT_TYPES
:
236 ExtensionInstallPrompt::Prompt::Prompt(PromptType type
)
238 is_showing_details_for_retained_files_(false),
239 is_showing_details_for_retained_devices_(false),
242 average_rating_(0.0),
244 show_user_count_(false),
245 has_webstore_data_(false) {
248 ExtensionInstallPrompt::Prompt::~Prompt() {
251 void ExtensionInstallPrompt::Prompt::SetPermissions(
252 const std::vector
<base::string16
>& permissions
,
253 PermissionsType permissions_type
) {
254 GetPermissionsForType(permissions_type
).permissions
= permissions
;
257 void ExtensionInstallPrompt::Prompt::SetPermissionsDetails(
258 const std::vector
<base::string16
>& details
,
259 PermissionsType permissions_type
) {
260 InstallPromptPermissions
& install_permissions
=
261 GetPermissionsForType(permissions_type
);
263 // Add a dash to the front of each permission detail.
264 for (const auto& details_entry
: details
) {
265 if (!details_entry
.empty()) {
266 std::vector
<base::string16
> detail_lines
;
267 base::SplitString(details_entry
, base::char16('\n'), &detail_lines
);
269 std::vector
<base::string16
> detail_lines_with_bullets
;
270 for (const auto& detail_line
: detail_lines
)
271 detail_lines_with_bullets
.push_back(base::ASCIIToUTF16("- ") +
274 install_permissions
.details
.push_back(
275 JoinString(detail_lines_with_bullets
, '\n'));
277 install_permissions
.details
.push_back(details_entry
);
281 install_permissions
.is_showing_details
.clear();
282 install_permissions
.is_showing_details
.insert(
283 install_permissions
.is_showing_details
.begin(), details
.size(), false);
286 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
289 bool is_showing_details
) {
291 case PERMISSIONS_DETAILS
:
292 prompt_permissions_
.is_showing_details
[index
] = is_showing_details
;
294 case WITHHELD_PERMISSIONS_DETAILS
:
295 withheld_prompt_permissions_
.is_showing_details
[index
] =
298 case RETAINED_FILES_DETAILS
:
299 is_showing_details_for_retained_files_
= is_showing_details
;
301 case RETAINED_DEVICES_DETAILS
:
302 is_showing_details_for_retained_devices_
= is_showing_details
;
307 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
308 const std::string
& localized_user_count
,
309 bool show_user_count
,
310 double average_rating
,
312 CHECK(AllowWebstoreData(type_
));
313 localized_user_count_
= localized_user_count
;
314 show_user_count_
= show_user_count
;
315 average_rating_
= average_rating
;
316 rating_count_
= rating_count
;
317 has_webstore_data_
= true;
320 base::string16
ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
321 int resource_id
= kTitleIds
[type_
];
323 if (type_
== INSTALL_PROMPT
) {
324 if (extension_
->is_app())
325 resource_id
= IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE
;
326 else if (extension_
->is_theme())
327 resource_id
= IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE
;
329 resource_id
= IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE
;
330 } else if (type_
== EXTERNAL_INSTALL_PROMPT
) {
331 return l10n_util::GetStringFUTF16(
332 resource_id
, base::UTF8ToUTF16(extension_
->name()));
333 } else if (type_
== REMOTE_INSTALL_PROMPT
) {
334 if (extension_
->is_app())
335 resource_id
= IDS_EXTENSION_REMOTE_INSTALL_APP_PROMPT_TITLE
;
337 resource_id
= IDS_EXTENSION_REMOTE_INSTALL_EXTENSION_PROMPT_TITLE
;
338 } else if (type_
== REPAIR_PROMPT
) {
339 if (extension_
->is_app())
340 resource_id
= IDS_EXTENSION_REPAIR_APP_PROMPT_TITLE
;
342 resource_id
= IDS_EXTENSION_REPAIR_EXTENSION_PROMPT_TITLE
;
343 } else if (type_
== DELEGATED_PERMISSIONS_PROMPT
) {
344 DCHECK(!delegated_username_
.empty());
345 if (extension_
->is_app())
346 resource_id
= IDS_EXTENSION_DELEGATED_INSTALL_APP_PROMPT_TITLE
;
348 resource_id
= IDS_EXTENSION_DELEGATED_INSTALL_EXTENSION_PROMPT_TITLE
;
349 return l10n_util::GetStringFUTF16(
350 resource_id
, base::UTF8ToUTF16(delegated_username_
));
353 return l10n_util::GetStringUTF16(resource_id
);
356 base::string16
ExtensionInstallPrompt::Prompt::GetHeading() const {
357 if (type_
== INLINE_INSTALL_PROMPT
) {
358 return base::UTF8ToUTF16(extension_
->name());
359 } else if (type_
== BUNDLE_INSTALL_PROMPT
) {
360 return bundle_
->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING
);
361 } else if (type_
== EXTERNAL_INSTALL_PROMPT
) {
362 int resource_id
= -1;
363 if (extension_
->is_app())
364 resource_id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP
;
365 else if (extension_
->is_theme())
366 resource_id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME
;
368 resource_id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION
;
369 return l10n_util::GetStringUTF16(resource_id
);
371 return l10n_util::GetStringFUTF16(
372 kHeadingIds
[type_
], base::UTF8ToUTF16(extension_
->name()));
376 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
377 if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
&& ShouldDisplayRevokeButton()) {
378 return kButtons
[type_
] | ui::DIALOG_BUTTON_OK
;
381 return kButtons
[type_
];
384 bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
385 if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
)
386 return ShouldDisplayRevokeButton();
388 if (kAcceptButtonIds
[type_
] == 0)
394 base::string16
ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
395 if (type_
== EXTERNAL_INSTALL_PROMPT
) {
397 if (extension_
->is_app())
398 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP
;
399 else if (extension_
->is_theme())
400 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME
;
402 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION
;
403 return l10n_util::GetStringUTF16(id
);
404 } else if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
) {
406 if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
408 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON
;
409 } else if (GetRetainedFileCount()) {
410 id
= IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON
;
412 DCHECK_LT(0U, GetRetainedDeviceCount());
413 id
= IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON
;
415 return l10n_util::GetStringUTF16(id
);
417 return l10n_util::GetStringUTF16(kAcceptButtonIds
[type_
]);
420 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
421 return kAbortButtonIds
[type_
] > 0;
424 base::string16
ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
425 CHECK(HasAbortButtonLabel());
426 return l10n_util::GetStringUTF16(kAbortButtonIds
[type_
]);
429 base::string16
ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
430 PermissionsType permissions_type
) const {
431 switch (permissions_type
) {
432 case REGULAR_PERMISSIONS
:
433 return l10n_util::GetStringUTF16(kPermissionsHeaderIds
[type_
]);
434 case WITHHELD_PERMISSIONS
:
435 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD
);
436 case ALL_PERMISSIONS
:
439 return base::string16();
443 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
444 const int kRetainedFilesMessageIDs
[6] = {
445 IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT
,
446 IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR
,
447 IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO
,
448 IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO
,
449 IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW
,
450 IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY
,
452 std::vector
<int> message_ids(
453 kRetainedFilesMessageIDs
,
454 kRetainedFilesMessageIDs
+ arraysize(kRetainedFilesMessageIDs
));
456 return l10n_util::GetPluralStringFUTF16(message_ids
, GetRetainedFileCount());
459 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedDevicesHeading()
461 const int kRetainedDevicesMessageIDs
[6] = {
462 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_DEFAULT
,
463 IDS_EXTENSION_PROMPT_RETAINED_DEVICE_SINGULAR
,
464 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_ZERO
,
465 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_TWO
,
466 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_FEW
,
467 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_MANY
,
469 std::vector
<int> message_ids(
470 kRetainedDevicesMessageIDs
,
471 kRetainedDevicesMessageIDs
+ arraysize(kRetainedDevicesMessageIDs
));
473 return l10n_util::GetPluralStringFUTF16(message_ids
,
474 GetRetainedDeviceCount());
477 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
478 return GetPermissionCount(ALL_PERMISSIONS
) > 0 ||
479 type_
== POST_INSTALL_PERMISSIONS_PROMPT
;
482 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
483 StarAppender appender
, void* data
) const {
485 CHECK(AllowWebstoreData(type_
));
486 int rating_integer
= floor(average_rating_
);
487 double rating_fractional
= average_rating_
- rating_integer
;
489 if (rating_fractional
> 0.66) {
493 if (rating_fractional
< 0.33 || rating_fractional
> 0.66) {
494 rating_fractional
= 0;
497 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
499 for (i
= 0; i
< rating_integer
; i
++) {
500 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON
), data
);
502 if (rating_fractional
) {
503 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT
), data
);
506 for (; i
< kMaxExtensionRating
; i
++) {
507 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF
), data
);
511 base::string16
ExtensionInstallPrompt::Prompt::GetRatingCount() const {
512 CHECK(AllowWebstoreData(type_
));
513 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT
,
514 base::IntToString16(rating_count_
));
517 base::string16
ExtensionInstallPrompt::Prompt::GetUserCount() const {
518 CHECK(AllowWebstoreData(type_
));
520 if (show_user_count_
) {
521 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT
,
522 base::UTF8ToUTF16(localized_user_count_
));
524 return base::string16();
527 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount(
528 PermissionsType permissions_type
) const {
529 switch (permissions_type
) {
530 case REGULAR_PERMISSIONS
:
531 return prompt_permissions_
.permissions
.size();
532 case WITHHELD_PERMISSIONS
:
533 return withheld_prompt_permissions_
.permissions
.size();
534 case ALL_PERMISSIONS
:
535 return prompt_permissions_
.permissions
.size() +
536 withheld_prompt_permissions_
.permissions
.size();
543 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount(
544 PermissionsType permissions_type
) const {
545 switch (permissions_type
) {
546 case REGULAR_PERMISSIONS
:
547 return prompt_permissions_
.details
.size();
548 case WITHHELD_PERMISSIONS
:
549 return withheld_prompt_permissions_
.details
.size();
550 case ALL_PERMISSIONS
:
551 return prompt_permissions_
.details
.size() +
552 withheld_prompt_permissions_
.details
.size();
559 base::string16
ExtensionInstallPrompt::Prompt::GetPermission(
561 PermissionsType permissions_type
) const {
562 const InstallPromptPermissions
& install_permissions
=
563 GetPermissionsForType(permissions_type
);
564 CHECK_LT(index
, install_permissions
.permissions
.size());
565 return install_permissions
.permissions
[index
];
568 base::string16
ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
570 PermissionsType permissions_type
) const {
571 const InstallPromptPermissions
& install_permissions
=
572 GetPermissionsForType(permissions_type
);
573 CHECK_LT(index
, install_permissions
.details
.size());
574 return install_permissions
.details
[index
];
577 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
578 DetailsType type
, size_t index
) const {
580 case PERMISSIONS_DETAILS
:
581 CHECK_LT(index
, prompt_permissions_
.is_showing_details
.size());
582 return prompt_permissions_
.is_showing_details
[index
];
583 case WITHHELD_PERMISSIONS_DETAILS
:
584 CHECK_LT(index
, withheld_prompt_permissions_
.is_showing_details
.size());
585 return withheld_prompt_permissions_
.is_showing_details
[index
];
586 case RETAINED_FILES_DETAILS
:
587 return is_showing_details_for_retained_files_
;
588 case RETAINED_DEVICES_DETAILS
:
589 return is_showing_details_for_retained_devices_
;
594 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
595 return retained_files_
.size();
598 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index
)
600 CHECK_LT(index
, retained_files_
.size());
601 return retained_files_
[index
].AsUTF16Unsafe();
604 size_t ExtensionInstallPrompt::Prompt::GetRetainedDeviceCount() const {
605 return retained_device_messages_
.size();
608 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedDeviceMessageString(
609 size_t index
) const {
610 CHECK_LT(index
, retained_device_messages_
.size());
611 return retained_device_messages_
[index
];
614 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeButton() const {
615 return !retained_files_
.empty() || !retained_device_messages_
.empty();
618 ExtensionInstallPrompt::Prompt::InstallPromptPermissions
&
619 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
620 PermissionsType permissions_type
) {
621 DCHECK_NE(ALL_PERMISSIONS
, permissions_type
);
622 return permissions_type
== REGULAR_PERMISSIONS
? prompt_permissions_
623 : withheld_prompt_permissions_
;
626 const ExtensionInstallPrompt::Prompt::InstallPromptPermissions
&
627 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
628 PermissionsType permissions_type
) const {
629 DCHECK_NE(ALL_PERMISSIONS
, permissions_type
);
630 return permissions_type
== REGULAR_PERMISSIONS
? prompt_permissions_
631 : withheld_prompt_permissions_
;
634 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
635 return !retained_files_
.empty();
639 scoped_refptr
<Extension
>
640 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
641 const base::DictionaryValue
* manifest
,
643 const std::string
& id
,
644 const std::string
& localized_name
,
645 const std::string
& localized_description
,
646 std::string
* error
) {
647 scoped_ptr
<base::DictionaryValue
> localized_manifest
;
648 if (!localized_name
.empty() || !localized_description
.empty()) {
649 localized_manifest
.reset(manifest
->DeepCopy());
650 if (!localized_name
.empty()) {
651 localized_manifest
->SetString(extensions::manifest_keys::kName
,
654 if (!localized_description
.empty()) {
655 localized_manifest
->SetString(extensions::manifest_keys::kDescription
,
656 localized_description
);
660 return Extension::Create(
663 localized_manifest
.get() ? *localized_manifest
.get() : *manifest
,
669 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents
* contents
)
670 : profile_(ProfileForWebContents(contents
)),
671 ui_loop_(base::MessageLoop::current()),
674 install_ui_(extensions::CreateExtensionInstallUI(
675 ProfileForWebContents(contents
))),
676 show_params_(new ExtensionInstallPromptShowParams(contents
)),
680 ExtensionInstallPrompt::ExtensionInstallPrompt(Profile
* profile
,
681 gfx::NativeWindow native_window
)
683 ui_loop_(base::MessageLoop::current()),
686 install_ui_(extensions::CreateExtensionInstallUI(profile
)),
688 new ExtensionInstallPromptShowParams(profile
, native_window
)),
692 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
695 void ExtensionInstallPrompt::ConfirmBundleInstall(
696 extensions::BundleInstaller
* bundle
,
697 const PermissionSet
* permissions
) {
698 DCHECK(ui_loop_
== base::MessageLoop::current());
700 custom_permissions_
= permissions
;
702 prompt_
= new Prompt(BUNDLE_INSTALL_PROMPT
);
707 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
709 const Extension
* extension
,
711 scoped_refptr
<Prompt
> prompt
) {
712 DCHECK(ui_loop_
== base::MessageLoop::current());
713 extension_
= extension
;
714 delegate_
= delegate
;
721 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
723 const Extension
* extension
,
724 const SkBitmap
* icon
,
725 const ShowDialogCallback
& show_dialog_callback
) {
726 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
728 extension_
= extension
;
730 ConfirmInstall(delegate
, extension
, show_dialog_callback
);
733 void ExtensionInstallPrompt::ConfirmInstall(
735 const Extension
* extension
,
736 const ShowDialogCallback
& show_dialog_callback
) {
737 DCHECK(ui_loop_
== base::MessageLoop::current());
738 extension_
= extension
;
739 delegate_
= delegate
;
740 prompt_
= new Prompt(INSTALL_PROMPT
);
741 show_dialog_callback_
= show_dialog_callback
;
743 // We special-case themes to not show any confirm UI. Instead they are
744 // immediately installed, and then we show an infobar (see OnInstallSuccess)
745 // to allow the user to revert if they don't like it.
747 // We don't do this in the case where off-store extension installs are
748 // disabled because in that case, we don't show the dangerous download UI, so
749 // we need the UI confirmation.
750 if (extension
->is_theme()) {
751 if (extension
->from_webstore() ||
752 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
753 delegate
->InstallUIProceed();
761 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedInstall(
763 const Extension
* extension
,
764 const std::string
& delegated_username
,
765 const SkBitmap
* icon
) {
766 DCHECK(ui_loop_
== base::MessageLoop::current());
767 delegate_
= delegate
;
768 extension_
= extension
;
769 delegated_username_
= delegated_username
;
771 prompt_
= new Prompt(DELEGATED_PERMISSIONS_PROMPT
);
775 void ExtensionInstallPrompt::ConfirmReEnable(Delegate
* delegate
,
776 const Extension
* extension
) {
777 DCHECK(ui_loop_
== base::MessageLoop::current());
778 extension_
= extension
;
779 delegate_
= delegate
;
780 bool is_remote_install
=
782 extensions::ExtensionPrefs::Get(profile_
)->HasDisableReason(
783 extension
->id(), extensions::Extension::DISABLE_REMOTE_INSTALL
);
785 extensions::util::IsEphemeralApp(extension
->id(), profile_
);
787 PromptType type
= UNSET_PROMPT_TYPE
;
789 type
= LAUNCH_PROMPT
;
790 else if (is_remote_install
)
791 type
= REMOTE_INSTALL_PROMPT
;
793 type
= RE_ENABLE_PROMPT
;
794 prompt_
= new Prompt(type
);
799 void ExtensionInstallPrompt::ConfirmExternalInstall(
801 const Extension
* extension
,
802 const ShowDialogCallback
& show_dialog_callback
,
803 scoped_refptr
<Prompt
> prompt
) {
804 DCHECK(ui_loop_
== base::MessageLoop::current());
805 extension_
= extension
;
806 delegate_
= delegate
;
808 show_dialog_callback_
= show_dialog_callback
;
813 void ExtensionInstallPrompt::ConfirmPermissions(
815 const Extension
* extension
,
816 const PermissionSet
* permissions
) {
817 DCHECK(ui_loop_
== base::MessageLoop::current());
818 extension_
= extension
;
819 custom_permissions_
= permissions
;
820 delegate_
= delegate
;
821 prompt_
= new Prompt(PERMISSIONS_PROMPT
);
826 void ExtensionInstallPrompt::ReviewPermissions(
828 const Extension
* extension
,
829 const std::vector
<base::FilePath
>& retained_file_paths
,
830 const std::vector
<base::string16
>& retained_device_messages
) {
831 DCHECK(ui_loop_
== base::MessageLoop::current());
832 extension_
= extension
;
833 prompt_
= new Prompt(POST_INSTALL_PERMISSIONS_PROMPT
);
834 prompt_
->set_retained_files(retained_file_paths
);
835 prompt_
->set_retained_device_messages(retained_device_messages
);
836 delegate_
= delegate
;
841 void ExtensionInstallPrompt::OnInstallSuccess(const Extension
* extension
,
843 extension_
= extension
;
846 install_ui_
->OnInstallSuccess(extension
, &icon_
);
849 void ExtensionInstallPrompt::OnInstallFailure(
850 const extensions::CrxInstallError
& error
) {
851 install_ui_
->OnInstallFailure(error
);
854 void ExtensionInstallPrompt::SetIcon(const SkBitmap
* image
) {
860 // Let's set default icon bitmap whose size is equal to the default icon's
861 // pixel size under maximal supported scale factor. If the bitmap is larger
862 // than the one we need, it will be scaled down by the ui code.
863 icon_
= GetDefaultIconBitmapForMaxScaleFactor(extension_
->is_app());
867 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image
& image
) {
868 SetIcon(image
.IsEmpty() ? NULL
: image
.ToSkBitmap());
872 void ExtensionInstallPrompt::LoadImageIfNeeded() {
873 // Bundle install prompts do not have an icon.
874 // Also |profile_| can be NULL in unit tests.
875 if (!icon_
.empty() || !profile_
) {
880 extensions::ExtensionResource image
= extensions::IconsInfo::GetIconResource(
882 extension_misc::EXTENSION_ICON_LARGE
,
883 ExtensionIconSet::MATCH_BIGGER
);
885 // Load the image asynchronously. The response will be sent to OnImageLoaded.
886 extensions::ImageLoader
* loader
= extensions::ImageLoader::Get(profile_
);
888 std::vector
<extensions::ImageLoader::ImageRepresentation
> images_list
;
889 images_list
.push_back(extensions::ImageLoader::ImageRepresentation(
891 extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE
,
893 ui::SCALE_FACTOR_100P
));
894 loader
->LoadImagesAsync(
897 base::Bind(&ExtensionInstallPrompt::OnImageLoaded
, AsWeakPtr()));
900 void ExtensionInstallPrompt::ShowConfirmation() {
901 scoped_refptr
<const PermissionSet
> permissions_to_display
;
902 if (custom_permissions_
.get()) {
903 permissions_to_display
= custom_permissions_
;
904 } else if (extension_
) {
905 // Initialize permissions if they have not already been set so that
906 // withheld permissions are displayed properly in the install prompt.
907 extensions::PermissionsUpdater(
908 profile_
, extensions::PermissionsUpdater::INIT_FLAG_TRANSIENT
)
909 .InitializePermissions(extension_
);
910 permissions_to_display
=
911 extension_
->permissions_data()->active_permissions();
912 // For delegated installs, all optional permissions are pre-approved by the
913 // person who triggers the install, so add them to the list.
914 if (prompt_
->type() == DELEGATED_PERMISSIONS_PROMPT
) {
915 scoped_refptr
<const PermissionSet
> optional_permissions
=
916 extensions::PermissionsParser::GetOptionalPermissions(extension_
);
917 permissions_to_display
= PermissionSet::CreateUnion(
918 permissions_to_display
.get(),
919 optional_permissions
.get());
923 if (permissions_to_display
.get() &&
925 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
926 extension_
->id()))) {
927 Manifest::Type type
=
928 extension_
? extension_
->GetType() : Manifest::TYPE_UNKNOWN
;
929 const extensions::PermissionMessageProvider
* message_provider
=
930 extensions::PermissionMessageProvider::Get();
931 prompt_
->SetPermissions(message_provider
->GetWarningMessages(
932 permissions_to_display
.get(), type
),
933 REGULAR_PERMISSIONS
);
934 prompt_
->SetPermissionsDetails(message_provider
->GetWarningMessagesDetails(
935 permissions_to_display
.get(), type
),
936 REGULAR_PERMISSIONS
);
938 scoped_refptr
<const extensions::PermissionSet
> withheld
=
939 extension_
->permissions_data()->withheld_permissions();
940 if (!withheld
->IsEmpty()) {
941 prompt_
->SetPermissions(
942 message_provider
->GetWarningMessages(withheld
.get(), type
),
943 PermissionsType::WITHHELD_PERMISSIONS
);
944 prompt_
->SetPermissionsDetails(
945 message_provider
->GetWarningMessagesDetails(withheld
.get(), type
),
946 PermissionsType::WITHHELD_PERMISSIONS
);
950 switch (prompt_
->type()) {
951 case PERMISSIONS_PROMPT
:
952 case RE_ENABLE_PROMPT
:
953 case INLINE_INSTALL_PROMPT
:
954 case EXTERNAL_INSTALL_PROMPT
:
957 case POST_INSTALL_PERMISSIONS_PROMPT
:
958 case REMOTE_INSTALL_PROMPT
:
960 case DELEGATED_PERMISSIONS_PROMPT
: {
961 prompt_
->set_extension(extension_
);
962 prompt_
->set_icon(gfx::Image::CreateFrom1xBitmap(icon_
));
963 prompt_
->set_delegated_username(delegated_username_
);
966 case BUNDLE_INSTALL_PROMPT
: {
967 prompt_
->set_bundle(bundle_
);
971 NOTREACHED() << "Unknown message";
975 g_last_prompt_type_for_tests
= prompt_
->type();
977 if (AutoConfirmPrompt(delegate_
))
980 if (show_params_
->WasParentDestroyed()) {
981 delegate_
->InstallUIAbort(false);
985 if (show_dialog_callback_
.is_null())
986 GetDefaultShowDialogCallback().Run(show_params_
.get(), delegate_
, prompt_
);
988 show_dialog_callback_
.Run(show_params_
.get(), delegate_
, prompt_
);