Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / extensions / extension_install_prompt.cc
blob8c8b1e282a83f981364aff82db88e1eb6292939a
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;
52 namespace {
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] = {
106 IDS_CANCEL,
107 IDS_CANCEL,
108 IDS_CANCEL,
109 IDS_CANCEL,
110 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
111 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
112 IDS_CLOSE,
113 IDS_CANCEL,
114 IDS_CANCEL,
115 IDS_CANCEL,
116 IDS_CANCEL,
117 IDS_CANCEL,
119 static const int
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:
150 return false;
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(
156 FROM_HERE,
157 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
158 base::Unretained(delegate)));
159 return true;
160 case extensions::ScopedTestDialogAutoConfirm::CANCEL:
161 base::ThreadTaskRunnerHandle::Get()->PostTask(
162 FROM_HERE,
163 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
164 base::Unretained(delegate),
165 true));
166 return true;
169 NOTREACHED();
170 return false;
173 Profile* ProfileForWebContents(content::WebContents* web_contents) {
174 if (!web_contents)
175 return NULL;
176 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
179 } // namespace
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) {
194 switch (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:
221 break;
223 return "OTHER";
226 ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
227 : type_(type),
228 is_showing_details_for_retained_files_(false),
229 is_showing_details_for_retained_devices_(false),
230 extension_(NULL),
231 bundle_(NULL),
232 average_rating_(0.0),
233 rating_count_(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("- ") +
259 detail_line);
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(
271 DetailsType type,
272 size_t index,
273 bool is_showing_details) {
274 switch (type) {
275 case PERMISSIONS_DETAILS:
276 prompt_permissions_.is_showing_details[index] = is_showing_details;
277 break;
278 case WITHHELD_PERMISSIONS_DETAILS:
279 withheld_prompt_permissions_.is_showing_details[index] =
280 is_showing_details;
281 break;
282 case RETAINED_FILES_DETAILS:
283 is_showing_details_for_retained_files_ = is_showing_details;
284 break;
285 case RETAINED_DEVICES_DETAILS:
286 is_showing_details_for_retained_devices_ = is_showing_details;
287 break;
291 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
292 const std::string& localized_user_count,
293 bool show_user_count,
294 double average_rating,
295 int rating_count) {
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;
319 else
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;
342 else
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;
349 else
350 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
351 } else if (type_ == POST_INSTALL_PERMISSIONS_PROMPT) {
352 if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
353 id =
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;
365 else
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;
370 else
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:
388 default:
389 NOTREACHED();
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()
400 const {
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 {
412 CHECK(appender);
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) {
418 rating_integer++;
421 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
422 rating_fractional = 0;
425 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
426 int i;
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);
432 i++;
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();
465 default:
466 NOTREACHED();
467 return 0u;
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();
481 default:
482 NOTREACHED();
483 return 0u;
487 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(
488 size_t index,
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(
497 size_t index,
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 {
507 switch (type) {
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_;
519 return false;
522 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
523 return retained_files_.size();
526 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
527 const {
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();
566 // static
567 scoped_refptr<Extension>
568 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
569 const base::DictionaryValue* manifest,
570 int flags,
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,
580 localized_name);
582 if (!localized_description.empty()) {
583 localized_manifest->SetString(extensions::manifest_keys::kDescription,
584 localized_description);
588 return Extension::Create(
589 base::FilePath(),
590 Manifest::INTERNAL,
591 localized_manifest.get() ? *localized_manifest.get() : *manifest,
592 flags,
594 error);
597 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents)
598 : profile_(ProfileForWebContents(contents)),
599 ui_loop_(base::MessageLoop::current()),
600 extension_(NULL),
601 bundle_(NULL),
602 install_ui_(extensions::CreateExtensionInstallUI(
603 ProfileForWebContents(contents))),
604 show_params_(new ExtensionInstallPromptShowParams(contents)),
605 delegate_(NULL) {
608 ExtensionInstallPrompt::ExtensionInstallPrompt(Profile* profile,
609 gfx::NativeWindow native_window)
610 : profile_(profile),
611 ui_loop_(base::MessageLoop::current()),
612 extension_(NULL),
613 bundle_(NULL),
614 install_ui_(extensions::CreateExtensionInstallUI(profile)),
615 show_params_(
616 new ExtensionInstallPromptShowParams(profile, native_window)),
617 delegate_(NULL) {
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());
628 bundle_ = bundle;
629 custom_permissions_ = permissions;
630 delegate_ = bundle;
631 prompt_ = new Prompt(BUNDLE_INSTALL_PROMPT);
633 SetIcon(icon);
634 ShowConfirmation();
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());
643 bundle_ = bundle;
644 delegated_username_ = delegated_username;
645 custom_permissions_ = permissions;
646 delegate_ = bundle;
647 prompt_ = new Prompt(DELEGATED_BUNDLE_PERMISSIONS_PROMPT);
649 SetIcon(icon);
650 ShowConfirmation();
653 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
654 Delegate* delegate,
655 const Extension* extension,
656 SkBitmap* icon,
657 scoped_refptr<Prompt> prompt) {
658 DCHECK(ui_loop_ == base::MessageLoop::current());
659 extension_ = extension;
660 delegate_ = delegate;
661 prompt_ = prompt;
663 SetIcon(icon);
664 ShowConfirmation();
667 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
668 Delegate* delegate,
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
673 // remaining fields.
674 extension_ = extension;
675 SetIcon(icon);
676 ConfirmInstall(delegate, extension, show_dialog_callback);
679 void ExtensionInstallPrompt::ConfirmInstall(
680 Delegate* delegate,
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();
700 return;
704 LoadImageIfNeeded();
707 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedInstall(
708 Delegate* delegate,
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;
716 SetIcon(icon);
717 prompt_ = new Prompt(DELEGATED_PERMISSIONS_PROMPT);
718 ShowConfirmation();
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 =
727 profile_ &&
728 extensions::ExtensionPrefs::Get(profile_)->HasDisableReason(
729 extension->id(), extensions::Extension::DISABLE_REMOTE_INSTALL);
730 bool is_ephemeral =
731 extensions::util::IsEphemeralApp(extension->id(), profile_);
733 PromptType type = UNSET_PROMPT_TYPE;
734 if (is_ephemeral)
735 type = LAUNCH_PROMPT;
736 else if (is_remote_install)
737 type = REMOTE_INSTALL_PROMPT;
738 else
739 type = RE_ENABLE_PROMPT;
740 prompt_ = new Prompt(type);
742 LoadImageIfNeeded();
745 void ExtensionInstallPrompt::ConfirmExternalInstall(
746 Delegate* delegate,
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;
753 prompt_ = prompt;
754 show_dialog_callback_ = show_dialog_callback;
756 LoadImageIfNeeded();
759 void ExtensionInstallPrompt::ConfirmPermissions(
760 Delegate* delegate,
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);
769 LoadImageIfNeeded();
772 void ExtensionInstallPrompt::ReviewPermissions(
773 Delegate* delegate,
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;
784 LoadImageIfNeeded();
787 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
788 SkBitmap* icon) {
789 extension_ = extension;
790 SetIcon(icon);
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) {
801 if (image)
802 icon_ = *image;
803 else
804 icon_ = SkBitmap();
805 if (icon_.empty()) {
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());
816 ShowConfirmation();
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_) {
823 ShowConfirmation();
824 return;
827 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
828 extension_,
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(
837 image,
838 extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE,
839 gfx::Size(),
840 ui::SCALE_FACTOR_100P));
841 loader->LoadImagesAsync(
842 extension_,
843 images_list,
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() &&
872 (!extension_ ||
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()
887 : nullptr;
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:
901 case INSTALL_PROMPT:
902 case LAUNCH_PROMPT:
903 case POST_INSTALL_PERMISSIONS_PROMPT:
904 case REMOTE_INSTALL_PROMPT:
905 case REPAIR_PROMPT:
906 case DELEGATED_PERMISSIONS_PROMPT: {
907 prompt_->set_extension(extension_);
908 break;
910 case BUNDLE_INSTALL_PROMPT:
911 case DELEGATED_BUNDLE_PERMISSIONS_PROMPT: {
912 prompt_->set_bundle(bundle_);
913 break;
915 default:
916 NOTREACHED() << "Unknown message";
917 return;
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_))
925 return;
927 if (show_params_->WasParentDestroyed()) {
928 delegate_->InstallUIAbort(false);
929 return;
932 if (show_dialog_callback_.is_null())
933 GetDefaultShowDialogCallback().Run(show_params_.get(), delegate_, prompt_);
934 else
935 show_dialog_callback_.Run(show_params_.get(), delegate_, prompt_);