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/location.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "chrome/browser/extensions/bundle_installer.h"
20 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
21 #include "chrome/browser/extensions/extension_util.h"
22 #include "chrome/browser/extensions/permissions_updater.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/extensions/extension_install_ui_factory.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/grit/chromium_strings.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "content/public/browser/web_contents.h"
29 #include "extensions/browser/extension_dialog_auto_confirm.h"
30 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_util.h"
32 #include "extensions/browser/image_loader.h"
33 #include "extensions/browser/install/extension_install_ui.h"
34 #include "extensions/common/constants.h"
35 #include "extensions/common/extension.h"
36 #include "extensions/common/extension_icon_set.h"
37 #include "extensions/common/extension_resource.h"
38 #include "extensions/common/feature_switch.h"
39 #include "extensions/common/manifest.h"
40 #include "extensions/common/manifest_constants.h"
41 #include "extensions/common/manifest_handlers/icons_handler.h"
42 #include "extensions/common/manifest_handlers/permissions_parser.h"
43 #include "extensions/common/permissions/permission_set.h"
44 #include "extensions/common/permissions/permissions_data.h"
45 #include "extensions/common/url_pattern.h"
46 #include "grit/theme_resources.h"
47 #include "ui/base/l10n/l10n_util.h"
48 #include "ui/base/resource/resource_bundle.h"
49 #include "ui/base/ui_base_types.h"
50 #include "ui/gfx/image/image.h"
52 using extensions::BundleInstaller
;
53 using extensions::Extension
;
54 using extensions::Manifest
;
55 using extensions::PermissionMessageString
;
56 using extensions::PermissionMessageStrings
;
57 using extensions::PermissionSet
;
61 bool AllowWebstoreData(ExtensionInstallPrompt::PromptType type
) {
62 return type
== ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
||
63 type
== ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT
||
64 type
== ExtensionInstallPrompt::REPAIR_PROMPT
;
67 static const int kTitleIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
68 IDS_EXTENSION_INSTALL_PROMPT_TITLE
,
69 IDS_EXTENSION_INSTALL_PROMPT_TITLE
,
70 0, // Heading for bundle installs depends on the bundle contents.
71 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE
,
72 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE
,
73 0, // External installs use different strings for extensions/apps/themes.
74 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE
,
75 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE
,
76 IDS_EXTENSION_REMOTE_INSTALL_PROMPT_TITLE
,
77 IDS_EXTENSION_REPAIR_PROMPT_TITLE
,
78 IDS_EXTENSION_DELEGATED_INSTALL_PROMPT_TITLE
,
79 0, // Heading for delegated bundle installs depends on the bundle contents.
81 static const int kButtons
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
82 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
83 ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
,
84 ui::DIALOG_BUTTON_OK
| 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 // The "OK" button in the post install permissions dialog allows revoking
89 // file/device access, and is only shown if such permissions exist; see
90 // ShouldDisplayRevokeButton().
91 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_OK
| ui::DIALOG_BUTTON_CANCEL
,
98 static const int kAcceptButtonIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
99 0, // Regular installs use different strings for extensions/apps/themes.
100 0, // Inline installs as well.
101 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
102 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON
,
103 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON
,
104 0, // External installs use different strings for extensions/apps/themes.
105 0, // Different strings depending on the files and devices retained.
106 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON
,
107 0, // Remote installs use different strings for extensions/apps.
108 0, // Repairs use different strings for extensions/apps.
109 0, // Delegated installs use different strings for extensions/apps/themes.
110 IDS_EXTENSION_PROMPT_INSTALL_BUTTON
,
112 static const int kAbortButtonIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
117 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON
,
118 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON
,
127 kPermissionsHeaderIds
[ExtensionInstallPrompt::NUM_PROMPT_TYPES
] = {
128 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
129 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
130 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO
,
131 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO
,
132 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO
,
133 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
134 IDS_EXTENSION_PROMPT_CAN_ACCESS
,
135 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
136 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
137 IDS_EXTENSION_PROMPT_CAN_ACCESS
,
138 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO
,
139 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO
,
142 // Returns bitmap for the default icon with size equal to the default icon's
143 // pixel size under maximal supported scale factor.
144 SkBitmap
GetDefaultIconBitmapForMaxScaleFactor(bool is_app
) {
145 const gfx::ImageSkia
& image
= is_app
?
146 extensions::util::GetDefaultAppIcon() :
147 extensions::util::GetDefaultExtensionIcon();
148 return image
.GetRepresentation(
149 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
152 // If auto confirm is enabled then posts a task to proceed with or cancel the
153 // install and returns true. Otherwise returns false.
154 bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate
* delegate
) {
155 switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
156 case extensions::ScopedTestDialogAutoConfirm::NONE
:
157 LOG(WARNING
) << "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 extensions::ScopedTestDialogAutoConfirm::ACCEPT
:
163 LOG(WARNING
) << "Proceeding!";
164 base::MessageLoop::current()->PostTask(
166 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed
,
167 base::Unretained(delegate
)));
169 case extensions::ScopedTestDialogAutoConfirm::CANCEL
:
170 LOG(WARNING
) << "Canceling!";
171 base::ThreadTaskRunnerHandle::Get()->PostTask(
173 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort
,
174 base::Unretained(delegate
),
183 Profile
* ProfileForWebContents(content::WebContents
* web_contents
) {
186 return Profile::FromBrowserContext(web_contents
->GetBrowserContext());
191 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
192 InstallPromptPermissions() {
194 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
195 ~InstallPromptPermissions() {
198 ExtensionInstallPrompt::PromptType
199 ExtensionInstallPrompt::g_last_prompt_type_for_tests
=
200 ExtensionInstallPrompt::UNSET_PROMPT_TYPE
;
202 // This should match the PromptType enum.
203 std::string
ExtensionInstallPrompt::PromptTypeToString(PromptType type
) {
205 case ExtensionInstallPrompt::INSTALL_PROMPT
:
206 return "INSTALL_PROMPT";
207 case ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
:
208 return "INLINE_INSTALL_PROMPT";
209 case ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT
:
210 return "BUNDLE_INSTALL_PROMPT";
211 case ExtensionInstallPrompt::RE_ENABLE_PROMPT
:
212 return "RE_ENABLE_PROMPT";
213 case ExtensionInstallPrompt::PERMISSIONS_PROMPT
:
214 return "PERMISSIONS_PROMPT";
215 case ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT
:
216 return "EXTERNAL_INSTALL_PROMPT";
217 case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT
:
218 return "POST_INSTALL_PERMISSIONS_PROMPT";
219 case ExtensionInstallPrompt::LAUNCH_PROMPT
:
220 return "LAUNCH_PROMPT";
221 case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT
:
222 return "REMOTE_INSTALL_PROMPT";
223 case ExtensionInstallPrompt::REPAIR_PROMPT
:
224 return "REPAIR_PROMPT";
225 case ExtensionInstallPrompt::DELEGATED_PERMISSIONS_PROMPT
:
226 return "DELEGATED_PERMISSIONS_PROMPT";
227 case ExtensionInstallPrompt::DELEGATED_BUNDLE_PERMISSIONS_PROMPT
:
228 return "DELEGATED_BUNDLE_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 PermissionMessageStrings
& permissions
,
253 PermissionsType permissions_type
) {
254 InstallPromptPermissions
& install_permissions
=
255 GetPermissionsForType(permissions_type
);
257 install_permissions
.permissions
.clear();
258 install_permissions
.details
.clear();
259 install_permissions
.is_showing_details
.clear();
261 for (const PermissionMessageString
& str
: permissions
) {
262 install_permissions
.permissions
.push_back(str
.message
);
263 // Add a dash to the front of each permission detail.
264 base::string16 details
;
265 if (!str
.submessages
.empty()) {
266 std::vector
<base::string16
> detail_lines_with_bullets
;
267 for (const auto& detail_line
: str
.submessages
) {
268 detail_lines_with_bullets
.push_back(base::ASCIIToUTF16("- ") +
272 details
= JoinString(detail_lines_with_bullets
, '\n');
274 install_permissions
.details
.push_back(details
);
275 install_permissions
.is_showing_details
.push_back(false);
279 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
282 bool is_showing_details
) {
284 case PERMISSIONS_DETAILS
:
285 prompt_permissions_
.is_showing_details
[index
] = is_showing_details
;
287 case WITHHELD_PERMISSIONS_DETAILS
:
288 withheld_prompt_permissions_
.is_showing_details
[index
] =
291 case RETAINED_FILES_DETAILS
:
292 is_showing_details_for_retained_files_
= is_showing_details
;
294 case RETAINED_DEVICES_DETAILS
:
295 is_showing_details_for_retained_devices_
= is_showing_details
;
300 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
301 const std::string
& localized_user_count
,
302 bool show_user_count
,
303 double average_rating
,
305 CHECK(AllowWebstoreData(type_
));
306 localized_user_count_
= localized_user_count
;
307 show_user_count_
= show_user_count
;
308 average_rating_
= average_rating
;
309 rating_count_
= rating_count
;
310 has_webstore_data_
= true;
313 base::string16
ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
314 int id
= kTitleIds
[type_
];
315 if (type_
== BUNDLE_INSTALL_PROMPT
||
316 type_
== DELEGATED_BUNDLE_PERMISSIONS_PROMPT
) {
317 return bundle_
->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING
);
319 if (type_
== DELEGATED_PERMISSIONS_PROMPT
) {
320 return l10n_util::GetStringFUTF16(id
, base::UTF8ToUTF16(extension_
->name()),
321 base::UTF8ToUTF16(delegated_username_
));
323 if (type_
== EXTERNAL_INSTALL_PROMPT
) {
324 if (extension_
->is_app())
325 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_APP
;
326 else if (extension_
->is_theme())
327 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_THEME
;
329 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_EXTENSION
;
331 return l10n_util::GetStringFUTF16(id
, base::UTF8ToUTF16(extension_
->name()));
334 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
335 if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
&& ShouldDisplayRevokeButton()) {
336 return kButtons
[type_
] | ui::DIALOG_BUTTON_OK
;
339 return kButtons
[type_
];
342 base::string16
ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
343 int id
= kAcceptButtonIds
[type_
];
345 if (type_
== INSTALL_PROMPT
|| type_
== INLINE_INSTALL_PROMPT
||
346 type_
== DELEGATED_PERMISSIONS_PROMPT
) {
347 if (extension_
->is_app())
348 id
= IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_APP
;
349 else if (extension_
->is_theme())
350 id
= IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_THEME
;
352 id
= IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION
;
353 } else if (type_
== EXTERNAL_INSTALL_PROMPT
) {
354 if (extension_
->is_app())
355 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP
;
356 else if (extension_
->is_theme())
357 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME
;
359 id
= IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION
;
360 } else if (type_
== POST_INSTALL_PERMISSIONS_PROMPT
) {
361 if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
363 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON
;
364 } else if (GetRetainedFileCount()) {
365 id
= IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON
;
366 } else if (GetRetainedDeviceCount()) {
367 id
= IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON
;
369 // If there are neither retained files nor devices, leave id 0 so there
370 // will be no "accept" button.
371 } else if (type_
== REMOTE_INSTALL_PROMPT
) {
372 if (extension_
->is_app())
373 id
= IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_APP
;
375 id
= IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_EXTENSION
;
376 } else if (type_
== REPAIR_PROMPT
) {
377 if (extension_
->is_app())
378 id
= IDS_EXTENSION_PROMPT_REPAIR_BUTTON_APP
;
380 id
= IDS_EXTENSION_PROMPT_REPAIR_BUTTON_EXTENSION
;
382 return id
? l10n_util::GetStringUTF16(id
) : base::string16();
385 base::string16
ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
386 return l10n_util::GetStringUTF16(kAbortButtonIds
[type_
]);
389 base::string16
ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
390 PermissionsType permissions_type
) const {
391 switch (permissions_type
) {
392 case REGULAR_PERMISSIONS
:
393 return l10n_util::GetStringUTF16(kPermissionsHeaderIds
[type_
]);
394 case WITHHELD_PERMISSIONS
:
395 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD
);
396 case ALL_PERMISSIONS
:
399 return base::string16();
403 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
404 return l10n_util::GetPluralStringFUTF16(
405 IDS_EXTENSION_PROMPT_RETAINED_FILES
, GetRetainedFileCount());
408 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedDevicesHeading()
410 return l10n_util::GetPluralStringFUTF16(
411 IDS_EXTENSION_PROMPT_RETAINED_DEVICES
, GetRetainedDeviceCount());
414 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
415 return GetPermissionCount(ALL_PERMISSIONS
) > 0 ||
416 type_
== POST_INSTALL_PERMISSIONS_PROMPT
;
419 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
420 StarAppender appender
, void* data
) const {
422 CHECK(AllowWebstoreData(type_
));
423 int rating_integer
= floor(average_rating_
);
424 double rating_fractional
= average_rating_
- rating_integer
;
426 if (rating_fractional
> 0.66) {
430 if (rating_fractional
< 0.33 || rating_fractional
> 0.66) {
431 rating_fractional
= 0;
434 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
436 for (i
= 0; i
< rating_integer
; i
++) {
437 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON
), data
);
439 if (rating_fractional
) {
440 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT
), data
);
443 for (; i
< kMaxExtensionRating
; i
++) {
444 appender(rb
.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF
), data
);
448 base::string16
ExtensionInstallPrompt::Prompt::GetRatingCount() const {
449 CHECK(AllowWebstoreData(type_
));
450 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT
,
451 base::IntToString16(rating_count_
));
454 base::string16
ExtensionInstallPrompt::Prompt::GetUserCount() const {
455 CHECK(AllowWebstoreData(type_
));
457 if (show_user_count_
) {
458 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT
,
459 base::UTF8ToUTF16(localized_user_count_
));
461 return base::string16();
464 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount(
465 PermissionsType permissions_type
) const {
466 switch (permissions_type
) {
467 case REGULAR_PERMISSIONS
:
468 return prompt_permissions_
.permissions
.size();
469 case WITHHELD_PERMISSIONS
:
470 return withheld_prompt_permissions_
.permissions
.size();
471 case ALL_PERMISSIONS
:
472 return prompt_permissions_
.permissions
.size() +
473 withheld_prompt_permissions_
.permissions
.size();
480 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount(
481 PermissionsType permissions_type
) const {
482 switch (permissions_type
) {
483 case REGULAR_PERMISSIONS
:
484 return prompt_permissions_
.details
.size();
485 case WITHHELD_PERMISSIONS
:
486 return withheld_prompt_permissions_
.details
.size();
487 case ALL_PERMISSIONS
:
488 return prompt_permissions_
.details
.size() +
489 withheld_prompt_permissions_
.details
.size();
496 base::string16
ExtensionInstallPrompt::Prompt::GetPermission(
498 PermissionsType permissions_type
) const {
499 const InstallPromptPermissions
& install_permissions
=
500 GetPermissionsForType(permissions_type
);
501 CHECK_LT(index
, install_permissions
.permissions
.size());
502 return install_permissions
.permissions
[index
];
505 base::string16
ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
507 PermissionsType permissions_type
) const {
508 const InstallPromptPermissions
& install_permissions
=
509 GetPermissionsForType(permissions_type
);
510 CHECK_LT(index
, install_permissions
.details
.size());
511 return install_permissions
.details
[index
];
514 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
515 DetailsType type
, size_t index
) const {
517 case PERMISSIONS_DETAILS
:
518 CHECK_LT(index
, prompt_permissions_
.is_showing_details
.size());
519 return prompt_permissions_
.is_showing_details
[index
];
520 case WITHHELD_PERMISSIONS_DETAILS
:
521 CHECK_LT(index
, withheld_prompt_permissions_
.is_showing_details
.size());
522 return withheld_prompt_permissions_
.is_showing_details
[index
];
523 case RETAINED_FILES_DETAILS
:
524 return is_showing_details_for_retained_files_
;
525 case RETAINED_DEVICES_DETAILS
:
526 return is_showing_details_for_retained_devices_
;
531 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
532 return retained_files_
.size();
535 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index
)
537 CHECK_LT(index
, retained_files_
.size());
538 return retained_files_
[index
].AsUTF16Unsafe();
541 size_t ExtensionInstallPrompt::Prompt::GetRetainedDeviceCount() const {
542 return retained_device_messages_
.size();
545 base::string16
ExtensionInstallPrompt::Prompt::GetRetainedDeviceMessageString(
546 size_t index
) const {
547 CHECK_LT(index
, retained_device_messages_
.size());
548 return retained_device_messages_
[index
];
551 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeButton() const {
552 return !retained_files_
.empty() || !retained_device_messages_
.empty();
555 ExtensionInstallPrompt::Prompt::InstallPromptPermissions
&
556 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
557 PermissionsType permissions_type
) {
558 DCHECK_NE(ALL_PERMISSIONS
, permissions_type
);
559 return permissions_type
== REGULAR_PERMISSIONS
? prompt_permissions_
560 : withheld_prompt_permissions_
;
563 const ExtensionInstallPrompt::Prompt::InstallPromptPermissions
&
564 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
565 PermissionsType permissions_type
) const {
566 DCHECK_NE(ALL_PERMISSIONS
, permissions_type
);
567 return permissions_type
== REGULAR_PERMISSIONS
? prompt_permissions_
568 : withheld_prompt_permissions_
;
571 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
572 return !retained_files_
.empty();
576 scoped_refptr
<Extension
>
577 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
578 const base::DictionaryValue
* manifest
,
580 const std::string
& id
,
581 const std::string
& localized_name
,
582 const std::string
& localized_description
,
583 std::string
* error
) {
584 scoped_ptr
<base::DictionaryValue
> localized_manifest
;
585 if (!localized_name
.empty() || !localized_description
.empty()) {
586 localized_manifest
.reset(manifest
->DeepCopy());
587 if (!localized_name
.empty()) {
588 localized_manifest
->SetString(extensions::manifest_keys::kName
,
591 if (!localized_description
.empty()) {
592 localized_manifest
->SetString(extensions::manifest_keys::kDescription
,
593 localized_description
);
597 return Extension::Create(
600 localized_manifest
.get() ? *localized_manifest
.get() : *manifest
,
606 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents
* contents
)
607 : profile_(ProfileForWebContents(contents
)),
608 ui_loop_(base::MessageLoop::current()),
611 install_ui_(extensions::CreateExtensionInstallUI(
612 ProfileForWebContents(contents
))),
613 show_params_(new ExtensionInstallPromptShowParams(contents
)),
617 ExtensionInstallPrompt::ExtensionInstallPrompt(Profile
* profile
,
618 gfx::NativeWindow native_window
)
620 ui_loop_(base::MessageLoop::current()),
623 install_ui_(extensions::CreateExtensionInstallUI(profile
)),
625 new ExtensionInstallPromptShowParams(profile
, native_window
)),
629 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
632 void ExtensionInstallPrompt::ConfirmBundleInstall(
633 extensions::BundleInstaller
* bundle
,
634 const SkBitmap
* icon
,
635 const PermissionSet
* permissions
) {
636 DCHECK(ui_loop_
== base::MessageLoop::current());
638 custom_permissions_
= permissions
;
640 prompt_
= new Prompt(BUNDLE_INSTALL_PROMPT
);
646 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedBundleInstall(
647 extensions::BundleInstaller
* bundle
,
648 const std::string
& delegated_username
,
649 const SkBitmap
* icon
,
650 const extensions::PermissionSet
* permissions
) {
651 DCHECK(ui_loop_
== base::MessageLoop::current());
653 delegated_username_
= delegated_username
;
654 custom_permissions_
= permissions
;
656 prompt_
= new Prompt(DELEGATED_BUNDLE_PERMISSIONS_PROMPT
);
662 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
664 const Extension
* extension
,
666 scoped_refptr
<Prompt
> prompt
) {
667 DCHECK(ui_loop_
== base::MessageLoop::current());
668 extension_
= extension
;
669 delegate_
= delegate
;
676 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
678 const Extension
* extension
,
679 const SkBitmap
* icon
,
680 const ShowDialogCallback
& show_dialog_callback
) {
681 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
683 extension_
= extension
;
685 ConfirmInstall(delegate
, extension
, show_dialog_callback
);
688 void ExtensionInstallPrompt::ConfirmInstall(
690 const Extension
* extension
,
691 const ShowDialogCallback
& show_dialog_callback
) {
692 DCHECK(ui_loop_
== base::MessageLoop::current());
693 extension_
= extension
;
694 delegate_
= delegate
;
695 prompt_
= new Prompt(INSTALL_PROMPT
);
696 show_dialog_callback_
= show_dialog_callback
;
698 // We special-case themes to not show any confirm UI. Instead they are
699 // immediately installed, and then we show an infobar (see OnInstallSuccess)
700 // to allow the user to revert if they don't like it.
702 // We don't do this in the case where off-store extension installs are
703 // disabled because in that case, we don't show the dangerous download UI, so
704 // we need the UI confirmation.
705 if (extension
->is_theme()) {
706 if (extension
->from_webstore() ||
707 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
708 delegate
->InstallUIProceed();
716 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedInstall(
718 const Extension
* extension
,
719 const std::string
& delegated_username
,
720 const SkBitmap
* icon
) {
721 DCHECK(ui_loop_
== base::MessageLoop::current());
722 delegate_
= delegate
;
723 extension_
= extension
;
724 delegated_username_
= delegated_username
;
726 prompt_
= new Prompt(DELEGATED_PERMISSIONS_PROMPT
);
730 void ExtensionInstallPrompt::ConfirmReEnable(Delegate
* delegate
,
731 const Extension
* extension
) {
732 DCHECK(ui_loop_
== base::MessageLoop::current());
733 extension_
= extension
;
734 delegate_
= delegate
;
735 bool is_remote_install
=
737 extensions::ExtensionPrefs::Get(profile_
)->HasDisableReason(
738 extension
->id(), extensions::Extension::DISABLE_REMOTE_INSTALL
);
740 extensions::util::IsEphemeralApp(extension
->id(), profile_
);
742 PromptType type
= UNSET_PROMPT_TYPE
;
744 type
= LAUNCH_PROMPT
;
745 else if (is_remote_install
)
746 type
= REMOTE_INSTALL_PROMPT
;
748 type
= RE_ENABLE_PROMPT
;
749 prompt_
= new Prompt(type
);
754 void ExtensionInstallPrompt::ConfirmExternalInstall(
756 const Extension
* extension
,
757 const ShowDialogCallback
& show_dialog_callback
,
758 scoped_refptr
<Prompt
> prompt
) {
759 DCHECK(ui_loop_
== base::MessageLoop::current());
760 extension_
= extension
;
761 delegate_
= delegate
;
763 show_dialog_callback_
= show_dialog_callback
;
768 void ExtensionInstallPrompt::ConfirmPermissions(
770 const Extension
* extension
,
771 const PermissionSet
* permissions
) {
772 DCHECK(ui_loop_
== base::MessageLoop::current());
773 extension_
= extension
;
774 custom_permissions_
= permissions
;
775 delegate_
= delegate
;
776 prompt_
= new Prompt(PERMISSIONS_PROMPT
);
781 void ExtensionInstallPrompt::ReviewPermissions(
783 const Extension
* extension
,
784 const std::vector
<base::FilePath
>& retained_file_paths
,
785 const std::vector
<base::string16
>& retained_device_messages
) {
786 DCHECK(ui_loop_
== base::MessageLoop::current());
787 extension_
= extension
;
788 prompt_
= new Prompt(POST_INSTALL_PERMISSIONS_PROMPT
);
789 prompt_
->set_retained_files(retained_file_paths
);
790 prompt_
->set_retained_device_messages(retained_device_messages
);
791 delegate_
= delegate
;
796 void ExtensionInstallPrompt::OnInstallSuccess(const Extension
* extension
,
798 extension_
= extension
;
801 install_ui_
->OnInstallSuccess(extension
, &icon_
);
804 void ExtensionInstallPrompt::OnInstallFailure(
805 const extensions::CrxInstallError
& error
) {
806 install_ui_
->OnInstallFailure(error
);
809 void ExtensionInstallPrompt::SetIcon(const SkBitmap
* image
) {
815 // Let's set default icon bitmap whose size is equal to the default icon's
816 // pixel size under maximal supported scale factor. If the bitmap is larger
817 // than the one we need, it will be scaled down by the ui code.
818 icon_
= GetDefaultIconBitmapForMaxScaleFactor(
819 extension_
? extension_
->is_app() : false);
823 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image
& image
) {
824 SetIcon(image
.IsEmpty() ? NULL
: image
.ToSkBitmap());
828 void ExtensionInstallPrompt::LoadImageIfNeeded() {
829 // Bundle install prompts do not have an icon.
830 // Also |profile_| can be NULL in unit tests.
831 if (!icon_
.empty() || !profile_
) {
836 extensions::ExtensionResource image
= extensions::IconsInfo::GetIconResource(
838 extension_misc::EXTENSION_ICON_LARGE
,
839 ExtensionIconSet::MATCH_BIGGER
);
841 // Load the image asynchronously. The response will be sent to OnImageLoaded.
842 extensions::ImageLoader
* loader
= extensions::ImageLoader::Get(profile_
);
844 std::vector
<extensions::ImageLoader::ImageRepresentation
> images_list
;
845 images_list
.push_back(extensions::ImageLoader::ImageRepresentation(
847 extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE
,
849 ui::SCALE_FACTOR_100P
));
850 loader
->LoadImagesAsync(
853 base::Bind(&ExtensionInstallPrompt::OnImageLoaded
, AsWeakPtr()));
856 void ExtensionInstallPrompt::ShowConfirmation() {
857 scoped_refptr
<const PermissionSet
> permissions_to_display
;
858 if (custom_permissions_
.get()) {
859 permissions_to_display
= custom_permissions_
;
860 } else if (extension_
) {
861 // Initialize permissions if they have not already been set so that
862 // withheld permissions are displayed properly in the install prompt.
863 extensions::PermissionsUpdater(
864 profile_
, extensions::PermissionsUpdater::INIT_FLAG_TRANSIENT
)
865 .InitializePermissions(extension_
);
866 permissions_to_display
=
867 extension_
->permissions_data()->active_permissions();
868 // For delegated installs, all optional permissions are pre-approved by the
869 // person who triggers the install, so add them to the list.
870 if (prompt_
->type() == DELEGATED_PERMISSIONS_PROMPT
||
871 prompt_
->type() == DELEGATED_BUNDLE_PERMISSIONS_PROMPT
) {
872 scoped_refptr
<const PermissionSet
> optional_permissions
=
873 extensions::PermissionsParser::GetOptionalPermissions(extension_
);
874 permissions_to_display
= PermissionSet::CreateUnion(
875 permissions_to_display
.get(),
876 optional_permissions
.get());
880 if (permissions_to_display
.get() &&
882 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
883 extension_
->id()))) {
884 Manifest::Type type
=
885 extension_
? extension_
->GetType() : Manifest::TYPE_UNKNOWN
;
886 const extensions::PermissionMessageProvider
* message_provider
=
887 extensions::PermissionMessageProvider::Get();
889 prompt_
->SetPermissions(message_provider
->GetPermissionMessageStrings(
890 permissions_to_display
.get(), type
),
891 REGULAR_PERMISSIONS
);
893 scoped_refptr
<const extensions::PermissionSet
> withheld
=
894 extension_
? extension_
->permissions_data()->withheld_permissions()
896 if (withheld
&& !withheld
->IsEmpty()) {
897 prompt_
->SetPermissions(
898 message_provider
->GetPermissionMessageStrings(withheld
.get(), type
),
899 PermissionsType::WITHHELD_PERMISSIONS
);
903 switch (prompt_
->type()) {
904 case PERMISSIONS_PROMPT
:
905 case RE_ENABLE_PROMPT
:
906 case INLINE_INSTALL_PROMPT
:
907 case EXTERNAL_INSTALL_PROMPT
:
910 case POST_INSTALL_PERMISSIONS_PROMPT
:
911 case REMOTE_INSTALL_PROMPT
:
913 case DELEGATED_PERMISSIONS_PROMPT
: {
914 prompt_
->set_extension(extension_
);
917 case BUNDLE_INSTALL_PROMPT
:
918 case DELEGATED_BUNDLE_PERMISSIONS_PROMPT
: {
919 prompt_
->set_bundle(bundle_
);
923 NOTREACHED() << "Unknown message";
926 prompt_
->set_delegated_username(delegated_username_
);
927 prompt_
->set_icon(gfx::Image::CreateFrom1xBitmap(icon_
));
929 g_last_prompt_type_for_tests
= prompt_
->type();
931 if (AutoConfirmPrompt(delegate_
))
934 if (show_params_
->WasParentDestroyed()) {
935 delegate_
->InstallUIAbort(false);
939 if (show_dialog_callback_
.is_null())
940 GetDefaultShowDialogCallback().Run(show_params_
.get(), delegate_
, prompt_
);
942 show_dialog_callback_
.Run(show_params_
.get(), delegate_
, prompt_
);