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