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 "base/location.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "chrome/browser/extensions/bundle_installer.h"
13 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
14 #include "chrome/browser/extensions/extension_util.h"
15 #include "chrome/browser/extensions/permissions_updater.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/extensions/extension_install_ui_factory.h"
18 #include "chrome/grit/chromium_strings.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "content/public/browser/web_contents.h"
21 #include "extensions/browser/extension_dialog_auto_confirm.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_util.h"
24 #include "extensions/browser/image_loader.h"
25 #include "extensions/browser/install/extension_install_ui.h"
26 #include "extensions/common/constants.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/extension_icon_set.h"
29 #include "extensions/common/extension_resource.h"
30 #include "extensions/common/feature_switch.h"
31 #include "extensions/common/manifest.h"
32 #include "extensions/common/manifest_constants.h"
33 #include "extensions/common/manifest_handlers/icons_handler.h"
34 #include "extensions/common/manifest_handlers/permissions_parser.h"
35 #include "extensions/common/permissions/permission_message_provider.h"
36 #include "extensions/common/permissions/permission_set.h"
37 #include "extensions/common/permissions/permissions_data.h"
38 #include "extensions/common/url_pattern.h"
39 #include "grit/theme_resources.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/resource/resource_bundle.h"
42 #include "ui/base/ui_base_types.h"
43 #include "ui/gfx/image/image.h"
45 using extensions::BundleInstaller
;
46 using extensions::Extension
;
47 using extensions::Manifest
;
48 using extensions::PermissionMessage
;
49 using extensions::PermissionMessages
;
50 using extensions::PermissionSet
;
54 bool AllowWebstoreData(ExtensionInstallPrompt::PromptType type
) {
55 return type
== ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
||
56 type
== ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT
||
57 type
== ExtensionInstallPrompt::REPAIR_PROMPT
;
60 static const int kTitleIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
61 IDS_EXTENSION_INSTALL_PROMPT_TITLE
,
62 IDS_EXTENSION_INSTALL_PROMPT_TITLE
,
63 0, // Heading for bundle installs depends on the bundle contents.
64 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE
,
65 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE
,
66 0, // External installs use different strings for extensions/apps/themes.
67 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE
,
68 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE
,
69 IDS_EXTENSION_REMOTE_INSTALL_PROMPT_TITLE
,
70 IDS_EXTENSION_REPAIR_PROMPT_TITLE
,
71 IDS_EXTENSION_DELEGATED_INSTALL_PROMPT_TITLE
,
72 0, // Heading for delegated bundle installs depends on the bundle contents.
74 static const int kButtons
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
75 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
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 // The "OK" button in the post install permissions dialog allows revoking
82 // file/device access, and is only shown if such permissions exist; see
83 // ShouldDisplayRevokeButton().
84 ui::DIALOG_BUTTON_CANCEL
,
85 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
86 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
87 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
88 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
89 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
91 static const int kAcceptButtonIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
92 0, // Regular installs use different strings for extensions/apps/themes.
93 0, // Inline installs as well.
94 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
95 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON
,
96 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON
,
97 0, // External installs use different strings for extensions/apps/themes.
98 0, // Different strings depending on the files and devices retained.
99 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON
,
100 0, // Remote installs use different strings for extensions/apps.
101 0, // Repairs use different strings for extensions/apps.
102 0, // Delegated installs use different strings for extensions/apps/themes.
103 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
105 static const int kAbortButtonIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
110 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON
,
111 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON
,
120 kPermissionsHeaderIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
121 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
122 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
123 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO
,
124 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO
,
125 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO
,
126 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
127 IDS_EXTENSION_PROMPT_CAN_ACCESS
,
128 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
129 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
130 IDS_EXTENSION_PROMPT_CAN_ACCESS
,
131 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
132 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO
,
135 // Returns bitmap for the default icon with size equal to the default icon's
136 // pixel size under maximal supported scale factor.
137 SkBitmap
GetDefaultIconBitmapForMaxScaleFactor(bool is_app
) {
138 const gfx::ImageSkia
& image
= is_app
?
139 extensions::util::GetDefaultAppIcon() :
140 extensions::util::GetDefaultExtensionIcon();
141 return image
.GetRepresentation(
142 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
145 // If auto confirm is enabled then posts a task to proceed with or cancel the
146 // install and returns true. Otherwise returns false.
147 bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate
* delegate
) {
148 switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
149 case extensions::ScopedTestDialogAutoConfirm::NONE
:
151 // We use PostTask instead of calling the delegate directly here, because in
152 // the real implementations it's highly likely the message loop will be
153 // pumping a few times before the user clicks accept or cancel.
154 case extensions::ScopedTestDialogAutoConfirm::ACCEPT
:
155 base::MessageLoop::current()->PostTask(
157 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed
,
158 base::Unretained(delegate
)));
160 case extensions::ScopedTestDialogAutoConfirm::CANCEL
:
161 base::ThreadTaskRunnerHandle::Get()->PostTask(
163 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort
,
164 base::Unretained(delegate
),
173 Profile
* ProfileForWebContents(content::WebContents
* web_contents
) {
176 return Profile::FromBrowserContext(web_contents
->GetBrowserContext());
181 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
182 InstallPromptPermissions() {
184 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
185 ~InstallPromptPermissions() {
188 ExtensionInstallPrompt::PromptType
189 ExtensionInstallPrompt::g_last_prompt_type_for_tests
=
190 ExtensionInstallPrompt::UNSET_PROMPT_TYPE
;
192 // This should match the PromptType enum.
193 std::string
ExtensionInstallPrompt::PromptTypeToString(PromptType type
) {
195 case ExtensionInstallPrompt::INSTALL_PROMPT
:
196 return "INSTALL_PROMPT";
197 case ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
:
198 return "INLINE_INSTALL_PROMPT";
199 case ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT
:
200 return "BUNDLE_INSTALL_PROMPT";
201 case ExtensionInstallPrompt::RE_ENABLE_PROMPT
:
202 return "RE_ENABLE_PROMPT";
203 case ExtensionInstallPrompt::PERMISSIONS_PROMPT
:
204 return "PERMISSIONS_PROMPT";
205 case ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT
:
206 return "EXTERNAL_INSTALL_PROMPT";
207 case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT
:
208 return "POST_INSTALL_PERMISSIONS_PROMPT";
209 case ExtensionInstallPrompt::LAUNCH_PROMPT
:
210 return "LAUNCH_PROMPT";
211 case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT
:
212 return "REMOTE_INSTALL_PROMPT";
213 case ExtensionInstallPrompt::REPAIR_PROMPT
:
214 return "REPAIR_PROMPT";
215 case ExtensionInstallPrompt::DELEGATED_PERMISSIONS_PROMPT
:
216 return "DELEGATED_PERMISSIONS_PROMPT";
217 case ExtensionInstallPrompt::DELEGATED_BUNDLE_PERMISSIONS_PROMPT
:
218 return "DELEGATED_BUNDLE_PERMISSIONS_PROMPT";
219 case ExtensionInstallPrompt::UNSET_PROMPT_TYPE
:
220 case ExtensionInstallPrompt::NUM_PROMPT_TYPES
:
226 ExtensionInstallPrompt::Prompt::Prompt(PromptType type
)
228 is_showing_details_for_retained_files_(false),
229 is_showing_details_for_retained_devices_(false),
232 average_rating_(0.0),
234 show_user_count_(false),
235 has_webstore_data_(false) {
238 ExtensionInstallPrompt::Prompt::~Prompt() {
241 void ExtensionInstallPrompt::Prompt::SetPermissions(
242 const PermissionMessages
& permissions
,
243 PermissionsType permissions_type
) {
244 InstallPromptPermissions
& install_permissions
=
245 GetPermissionsForType(permissions_type
);
247 install_permissions
.permissions
.clear();
248 install_permissions
.details
.clear();
249 install_permissions
.is_showing_details
.clear();
251 for (const PermissionMessage
& msg
: permissions
) {
252 install_permissions
.permissions
.push_back(msg
.message());
253 // Add a dash to the front of each permission detail.
254 base::string16 details
;
255 if (!msg
.submessages().empty()) {
256 std::vector
<base::string16
> detail_lines_with_bullets
;
257 for (const auto& detail_line
: msg
.submessages()) {
258 detail_lines_with_bullets
.push_back(base::ASCIIToUTF16("- ") +
262 details
= base::JoinString(detail_lines_with_bullets
,
263 base::ASCIIToUTF16("\n"));
265 install_permissions
.details
.push_back(details
);
266 install_permissions
.is_showing_details
.push_back(false);
270 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
273 bool is_showing_details
) {
275 case PERMISSIONS_DETAILS
:
276 prompt_permissions_
.is_showing_details
[index
] = is_showing_details
;
278 case WITHHELD_PERMISSIONS_DETAILS
:
279 withheld_prompt_permissions_
.is_showing_details
[index
] =
282 case RETAINED_FILES_DETAILS
:
283 is_showing_details_for_retained_files_
= is_showing_details
;
285 case RETAINED_DEVICES_DETAILS
:
286 is_showing_details_for_retained_devices_
= is_showing_details
;
291 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
292 const std::string
& localized_user_count
,
293 bool show_user_count
,
294 double average_rating
,
296 CHECK(AllowWebstoreData(type_
));
297 localized_user_count_
= localized_user_count
;
298 show_user_count_
= show_user_count
;
299 average_rating_
= average_rating
;
300 rating_count_
= rating_count
;
301 has_webstore_data_
= true;
304 base::string16
ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
305 int id
= kTitleIds
[type_
];
306 if (type_
== BUNDLE_INSTALL_PROMPT
||
307 type_
== DELEGATED_BUNDLE_PERMISSIONS_PROMPT
) {
308 return bundle_
->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING
);
310 if (type_
== DELEGATED_PERMISSIONS_PROMPT
) {
311 return l10n_util::GetStringFUTF16(id
, base::UTF8ToUTF16(extension_
->name()),
312 base::UTF8ToUTF16(delegated_username_
));
314 if (type_
== EXTERNAL_INSTALL_PROMPT
) {
315 if (extension_
->is_app())
316 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_APP
;
317 else if (extension_
->is_theme())
318 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_THEME
;
320 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_EXTENSION
;
322 return l10n_util::GetStringFUTF16(id
, base::UTF8ToUTF16(extension_
->name()));
325 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
326 if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
&& ShouldDisplayRevokeButton()) {
327 return kButtons
[type_
] | ui::DIALOG_BUTTON_OK
;
330 return kButtons
[type_
];
333 base::string16
ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
334 int id
= kAcceptButtonIds
[type_
];
336 if (type_
== INSTALL_PROMPT
|| type_
== INLINE_INSTALL_PROMPT
||
337 type_
== DELEGATED_PERMISSIONS_PROMPT
) {
338 if (extension_
->is_app())
339 id
= IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_APP
;
340 else if (extension_
->is_theme())
341 id
= IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_THEME
;
343 id
= IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION
;
344 } else if (type_
== EXTERNAL_INSTALL_PROMPT
) {
345 if (extension_
->is_app())
346 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP
;
347 else if (extension_
->is_theme())
348 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME
;
350 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION
;
351 } else if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
) {
352 if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
354 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON
;
355 } else if (GetRetainedFileCount()) {
356 id
= IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON
;
357 } else if (GetRetainedDeviceCount()) {
358 id
= IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON
;
360 // If there are neither retained files nor devices, leave id 0 so there
361 // will be no "accept" button.
362 } else if (type_
== REMOTE_INSTALL_PROMPT
) {
363 if (extension_
->is_app())
364 id
= IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_APP
;
366 id
= IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_EXTENSION
;
367 } else if (type_
== REPAIR_PROMPT
) {
368 if (extension_
->is_app())
369 id
= IDS_EXTENSION_PROMPT_REPAIR_BUTTON_APP
;
371 id
= IDS_EXTENSION_PROMPT_REPAIR_BUTTON_EXTENSION
;
373 return id
? l10n_util::GetStringUTF16(id
) : base::string16();
376 base::string16
ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
377 return l10n_util::GetStringUTF16(kAbortButtonIds
[type_
]);
380 base::string16
ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
381 PermissionsType permissions_type
) const {
382 switch (permissions_type
) {
383 case REGULAR_PERMISSIONS
:
384 return l10n_util::GetStringUTF16(kPermissionsHeaderIds
[type_
]);
385 case WITHHELD_PERMISSIONS
:
386 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD
);
387 case ALL_PERMISSIONS
:
390 return base::string16();
394 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
395 return l10n_util::GetPluralStringFUTF16(
396 IDS_EXTENSION_PROMPT_RETAINED_FILES
, GetRetainedFileCount());
399 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedDevicesHeading()
401 return l10n_util::GetPluralStringFUTF16(
402 IDS_EXTENSION_PROMPT_RETAINED_DEVICES
, GetRetainedDeviceCount());
405 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
406 return GetPermissionCount(ALL_PERMISSIONS
) > 0 ||
407 type_
== POST_INSTALL_PERMISSIONS_PROMPT
;
410 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
411 StarAppender appender
, void* data
) const {
413 CHECK(AllowWebstoreData(type_
));
414 int rating_integer
= floor(average_rating_
);
415 double rating_fractional
= average_rating_
- rating_integer
;
417 if (rating_fractional
> 0.66) {
421 if (rating_fractional
< 0.33 || rating_fractional
> 0.66) {
422 rating_fractional
= 0;
425 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
427 for (i
= 0; i
< rating_integer
; i
++) {
428 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON
), data
);
430 if (rating_fractional
) {
431 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT
), data
);
434 for (; i
< kMaxExtensionRating
; i
++) {
435 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF
), data
);
439 base::string16
ExtensionInstallPrompt::Prompt::GetRatingCount() const {
440 CHECK(AllowWebstoreData(type_
));
441 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT
,
442 base::IntToString16(rating_count_
));
445 base::string16
ExtensionInstallPrompt::Prompt::GetUserCount() const {
446 CHECK(AllowWebstoreData(type_
));
448 if (show_user_count_
) {
449 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT
,
450 base::UTF8ToUTF16(localized_user_count_
));
452 return base::string16();
455 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount(
456 PermissionsType permissions_type
) const {
457 switch (permissions_type
) {
458 case REGULAR_PERMISSIONS
:
459 return prompt_permissions_
.permissions
.size();
460 case WITHHELD_PERMISSIONS
:
461 return withheld_prompt_permissions_
.permissions
.size();
462 case ALL_PERMISSIONS
:
463 return prompt_permissions_
.permissions
.size() +
464 withheld_prompt_permissions_
.permissions
.size();
471 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount(
472 PermissionsType permissions_type
) const {
473 switch (permissions_type
) {
474 case REGULAR_PERMISSIONS
:
475 return prompt_permissions_
.details
.size();
476 case WITHHELD_PERMISSIONS
:
477 return withheld_prompt_permissions_
.details
.size();
478 case ALL_PERMISSIONS
:
479 return prompt_permissions_
.details
.size() +
480 withheld_prompt_permissions_
.details
.size();
487 base::string16
ExtensionInstallPrompt::Prompt::GetPermission(
489 PermissionsType permissions_type
) const {
490 const InstallPromptPermissions
& install_permissions
=
491 GetPermissionsForType(permissions_type
);
492 CHECK_LT(index
, install_permissions
.permissions
.size());
493 return install_permissions
.permissions
[index
];
496 base::string16
ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
498 PermissionsType permissions_type
) const {
499 const InstallPromptPermissions
& install_permissions
=
500 GetPermissionsForType(permissions_type
);
501 CHECK_LT(index
, install_permissions
.details
.size());
502 return install_permissions
.details
[index
];
505 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
506 DetailsType type
, size_t index
) const {
508 case PERMISSIONS_DETAILS
:
509 CHECK_LT(index
, prompt_permissions_
.is_showing_details
.size());
510 return prompt_permissions_
.is_showing_details
[index
];
511 case WITHHELD_PERMISSIONS_DETAILS
:
512 CHECK_LT(index
, withheld_prompt_permissions_
.is_showing_details
.size());
513 return withheld_prompt_permissions_
.is_showing_details
[index
];
514 case RETAINED_FILES_DETAILS
:
515 return is_showing_details_for_retained_files_
;
516 case RETAINED_DEVICES_DETAILS
:
517 return is_showing_details_for_retained_devices_
;
522 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
523 return retained_files_
.size();
526 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index
)
528 CHECK_LT(index
, retained_files_
.size());
529 return retained_files_
[index
].AsUTF16Unsafe();
532 size_t ExtensionInstallPrompt::Prompt::GetRetainedDeviceCount() const {
533 return retained_device_messages_
.size();
536 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedDeviceMessageString(
537 size_t index
) const {
538 CHECK_LT(index
, retained_device_messages_
.size());
539 return retained_device_messages_
[index
];
542 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeButton() const {
543 return !retained_files_
.empty() || !retained_device_messages_
.empty();
546 ExtensionInstallPrompt::Prompt::InstallPromptPermissions
&
547 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
548 PermissionsType permissions_type
) {
549 DCHECK_NE(ALL_PERMISSIONS
, permissions_type
);
550 return permissions_type
== REGULAR_PERMISSIONS
? prompt_permissions_
551 : withheld_prompt_permissions_
;
554 const ExtensionInstallPrompt::Prompt::InstallPromptPermissions
&
555 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
556 PermissionsType permissions_type
) const {
557 DCHECK_NE(ALL_PERMISSIONS
, permissions_type
);
558 return permissions_type
== REGULAR_PERMISSIONS
? prompt_permissions_
559 : withheld_prompt_permissions_
;
562 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
563 return !retained_files_
.empty();
567 scoped_refptr
<Extension
>
568 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
569 const base::DictionaryValue
* manifest
,
571 const std::string
& id
,
572 const std::string
& localized_name
,
573 const std::string
& localized_description
,
574 std::string
* error
) {
575 scoped_ptr
<base::DictionaryValue
> localized_manifest
;
576 if (!localized_name
.empty() || !localized_description
.empty()) {
577 localized_manifest
.reset(manifest
->DeepCopy());
578 if (!localized_name
.empty()) {
579 localized_manifest
->SetString(extensions::manifest_keys::kName
,
582 if (!localized_description
.empty()) {
583 localized_manifest
->SetString(extensions::manifest_keys::kDescription
,
584 localized_description
);
588 return Extension::Create(
591 localized_manifest
.get() ? *localized_manifest
.get() : *manifest
,
597 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents
* contents
)
598 : profile_(ProfileForWebContents(contents
)),
599 ui_loop_(base::MessageLoop::current()),
602 install_ui_(extensions::CreateExtensionInstallUI(
603 ProfileForWebContents(contents
))),
604 show_params_(new ExtensionInstallPromptShowParams(contents
)),
608 ExtensionInstallPrompt::ExtensionInstallPrompt(Profile
* profile
,
609 gfx::NativeWindow native_window
)
611 ui_loop_(base::MessageLoop::current()),
614 install_ui_(extensions::CreateExtensionInstallUI(profile
)),
616 new ExtensionInstallPromptShowParams(profile
, native_window
)),
620 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
623 void ExtensionInstallPrompt::ConfirmBundleInstall(
624 extensions::BundleInstaller
* bundle
,
625 const SkBitmap
* icon
,
626 const PermissionSet
* permissions
) {
627 DCHECK(ui_loop_
== base::MessageLoop::current());
629 custom_permissions_
= permissions
;
631 prompt_
= new Prompt(BUNDLE_INSTALL_PROMPT
);
637 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedBundleInstall(
638 extensions::BundleInstaller
* bundle
,
639 const std::string
& delegated_username
,
640 const SkBitmap
* icon
,
641 const extensions::PermissionSet
* permissions
) {
642 DCHECK(ui_loop_
== base::MessageLoop::current());
644 delegated_username_
= delegated_username
;
645 custom_permissions_
= permissions
;
647 prompt_
= new Prompt(DELEGATED_BUNDLE_PERMISSIONS_PROMPT
);
653 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
655 const Extension
* extension
,
657 scoped_refptr
<Prompt
> prompt
) {
658 DCHECK(ui_loop_
== base::MessageLoop::current());
659 extension_
= extension
;
660 delegate_
= delegate
;
667 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
669 const Extension
* extension
,
670 const SkBitmap
* icon
,
671 const ShowDialogCallback
& show_dialog_callback
) {
672 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
674 extension_
= extension
;
676 ConfirmInstall(delegate
, extension
, show_dialog_callback
);
679 void ExtensionInstallPrompt::ConfirmInstall(
681 const Extension
* extension
,
682 const ShowDialogCallback
& show_dialog_callback
) {
683 DCHECK(ui_loop_
== base::MessageLoop::current());
684 extension_
= extension
;
685 delegate_
= delegate
;
686 prompt_
= new Prompt(INSTALL_PROMPT
);
687 show_dialog_callback_
= show_dialog_callback
;
689 // We special-case themes to not show any confirm UI. Instead they are
690 // immediately installed, and then we show an infobar (see OnInstallSuccess)
691 // to allow the user to revert if they don't like it.
693 // We don't do this in the case where off-store extension installs are
694 // disabled because in that case, we don't show the dangerous download UI, so
695 // we need the UI confirmation.
696 if (extension
->is_theme()) {
697 if (extension
->from_webstore() ||
698 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
699 delegate
->InstallUIProceed();
707 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedInstall(
709 const Extension
* extension
,
710 const std::string
& delegated_username
,
711 const SkBitmap
* icon
) {
712 DCHECK(ui_loop_
== base::MessageLoop::current());
713 delegate_
= delegate
;
714 extension_
= extension
;
715 delegated_username_
= delegated_username
;
717 prompt_
= new Prompt(DELEGATED_PERMISSIONS_PROMPT
);
721 void ExtensionInstallPrompt::ConfirmReEnable(Delegate
* delegate
,
722 const Extension
* extension
) {
723 DCHECK(ui_loop_
== base::MessageLoop::current());
724 extension_
= extension
;
725 delegate_
= delegate
;
726 bool is_remote_install
=
728 extensions::ExtensionPrefs::Get(profile_
)->HasDisableReason(
729 extension
->id(), extensions::Extension::DISABLE_REMOTE_INSTALL
);
731 extensions::util::IsEphemeralApp(extension
->id(), profile_
);
733 PromptType type
= UNSET_PROMPT_TYPE
;
735 type
= LAUNCH_PROMPT
;
736 else if (is_remote_install
)
737 type
= REMOTE_INSTALL_PROMPT
;
739 type
= RE_ENABLE_PROMPT
;
740 prompt_
= new Prompt(type
);
745 void ExtensionInstallPrompt::ConfirmExternalInstall(
747 const Extension
* extension
,
748 const ShowDialogCallback
& show_dialog_callback
,
749 scoped_refptr
<Prompt
> prompt
) {
750 DCHECK(ui_loop_
== base::MessageLoop::current());
751 extension_
= extension
;
752 delegate_
= delegate
;
754 show_dialog_callback_
= show_dialog_callback
;
759 void ExtensionInstallPrompt::ConfirmPermissions(
761 const Extension
* extension
,
762 const PermissionSet
* permissions
) {
763 DCHECK(ui_loop_
== base::MessageLoop::current());
764 extension_
= extension
;
765 custom_permissions_
= permissions
;
766 delegate_
= delegate
;
767 prompt_
= new Prompt(PERMISSIONS_PROMPT
);
772 void ExtensionInstallPrompt::ReviewPermissions(
774 const Extension
* extension
,
775 const std::vector
<base::FilePath
>& retained_file_paths
,
776 const std::vector
<base::string16
>& retained_device_messages
) {
777 DCHECK(ui_loop_
== base::MessageLoop::current());
778 extension_
= extension
;
779 prompt_
= new Prompt(POST_INSTALL_PERMISSIONS_PROMPT
);
780 prompt_
->set_retained_files(retained_file_paths
);
781 prompt_
->set_retained_device_messages(retained_device_messages
);
782 delegate_
= delegate
;
787 void ExtensionInstallPrompt::OnInstallSuccess(const Extension
* extension
,
789 extension_
= extension
;
792 install_ui_
->OnInstallSuccess(extension
, &icon_
);
795 void ExtensionInstallPrompt::OnInstallFailure(
796 const extensions::CrxInstallError
& error
) {
797 install_ui_
->OnInstallFailure(error
);
800 void ExtensionInstallPrompt::SetIcon(const SkBitmap
* image
) {
806 // Let's set default icon bitmap whose size is equal to the default icon's
807 // pixel size under maximal supported scale factor. If the bitmap is larger
808 // than the one we need, it will be scaled down by the ui code.
809 icon_
= GetDefaultIconBitmapForMaxScaleFactor(
810 extension_
? extension_
->is_app() : false);
814 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image
& image
) {
815 SetIcon(image
.IsEmpty() ? NULL
: image
.ToSkBitmap());
819 void ExtensionInstallPrompt::LoadImageIfNeeded() {
820 // Bundle install prompts do not have an icon.
821 // Also |profile_| can be NULL in unit tests.
822 if (!icon_
.empty() || !profile_
) {
827 extensions::ExtensionResource image
= extensions::IconsInfo::GetIconResource(
829 extension_misc::EXTENSION_ICON_LARGE
,
830 ExtensionIconSet::MATCH_BIGGER
);
832 // Load the image asynchronously. The response will be sent to OnImageLoaded.
833 extensions::ImageLoader
* loader
= extensions::ImageLoader::Get(profile_
);
835 std::vector
<extensions::ImageLoader::ImageRepresentation
> images_list
;
836 images_list
.push_back(extensions::ImageLoader::ImageRepresentation(
838 extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE
,
840 ui::SCALE_FACTOR_100P
));
841 loader
->LoadImagesAsync(
844 base::Bind(&ExtensionInstallPrompt::OnImageLoaded
, AsWeakPtr()));
847 void ExtensionInstallPrompt::ShowConfirmation() {
848 scoped_refptr
<const PermissionSet
> permissions_to_display
;
849 if (custom_permissions_
.get()) {
850 permissions_to_display
= custom_permissions_
;
851 } else if (extension_
) {
852 // Initialize permissions if they have not already been set so that
853 // withheld permissions are displayed properly in the install prompt.
854 extensions::PermissionsUpdater(
855 profile_
, extensions::PermissionsUpdater::INIT_FLAG_TRANSIENT
)
856 .InitializePermissions(extension_
);
857 permissions_to_display
=
858 extension_
->permissions_data()->active_permissions();
859 // For delegated installs, all optional permissions are pre-approved by the
860 // person who triggers the install, so add them to the list.
861 if (prompt_
->type() == DELEGATED_PERMISSIONS_PROMPT
||
862 prompt_
->type() == DELEGATED_BUNDLE_PERMISSIONS_PROMPT
) {
863 scoped_refptr
<const PermissionSet
> optional_permissions
=
864 extensions::PermissionsParser::GetOptionalPermissions(extension_
);
865 permissions_to_display
= PermissionSet::CreateUnion(
866 permissions_to_display
.get(),
867 optional_permissions
.get());
871 if (permissions_to_display
.get() &&
873 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
874 extension_
->id()))) {
875 Manifest::Type type
=
876 extension_
? extension_
->GetType() : Manifest::TYPE_UNKNOWN
;
877 const extensions::PermissionMessageProvider
* message_provider
=
878 extensions::PermissionMessageProvider::Get();
880 prompt_
->SetPermissions(message_provider
->GetPermissionMessages(
881 message_provider
->GetAllPermissionIDs(
882 permissions_to_display
.get(), type
)),
883 REGULAR_PERMISSIONS
);
885 scoped_refptr
<const extensions::PermissionSet
> withheld
=
886 extension_
? extension_
->permissions_data()->withheld_permissions()
888 if (withheld
&& !withheld
->IsEmpty()) {
889 prompt_
->SetPermissions(
890 message_provider
->GetPermissionMessages(
891 message_provider
->GetAllPermissionIDs(withheld
.get(), type
)),
892 WITHHELD_PERMISSIONS
);
896 switch (prompt_
->type()) {
897 case PERMISSIONS_PROMPT
:
898 case RE_ENABLE_PROMPT
:
899 case INLINE_INSTALL_PROMPT
:
900 case EXTERNAL_INSTALL_PROMPT
:
903 case POST_INSTALL_PERMISSIONS_PROMPT
:
904 case REMOTE_INSTALL_PROMPT
:
906 case DELEGATED_PERMISSIONS_PROMPT
: {
907 prompt_
->set_extension(extension_
);
910 case BUNDLE_INSTALL_PROMPT
:
911 case DELEGATED_BUNDLE_PERMISSIONS_PROMPT
: {
912 prompt_
->set_bundle(bundle_
);
916 NOTREACHED() << "Unknown message";
919 prompt_
->set_delegated_username(delegated_username_
);
920 prompt_
->set_icon(gfx::Image::CreateFrom1xBitmap(icon_
));
922 g_last_prompt_type_for_tests
= prompt_
->type();
924 if (AutoConfirmPrompt(delegate_
))
927 if (show_params_
->WasParentDestroyed()) {
928 delegate_
->InstallUIAbort(false);
932 if (show_dialog_callback_
.is_null())
933 GetDefaultShowDialogCallback().Run(show_params_
.get(), delegate_
, prompt_
);
935 show_dialog_callback_
.Run(show_params_
.get(), delegate_
, prompt_
);