ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / extensions / extension_install_prompt.cc
blob00146cf1364c30d980fbbddfbca2e15075278bb8
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/permissions/permission_message_provider.h"
40 #include "extensions/common/permissions/permission_set.h"
41 #include "extensions/common/permissions/permissions_data.h"
42 #include "extensions/common/url_pattern.h"
43 #include "grit/theme_resources.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/base/ui_base_types.h"
47 #include "ui/gfx/image/image.h"
49 using extensions::BundleInstaller;
50 using extensions::Extension;
51 using extensions::Manifest;
52 using extensions::PermissionSet;
54 namespace {
56 bool AllowWebstoreData(ExtensionInstallPrompt::PromptType type) {
57 return type == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT ||
58 type == ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT ||
59 type == ExtensionInstallPrompt::REPAIR_PROMPT;
62 static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
63 0, // The regular install prompt depends on what's being installed.
64 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
65 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
66 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
67 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
68 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
69 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
70 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE,
71 0, // The remote install prompt depends on what's being installed.
72 0, // The repair install prompt depends on what's being installed.
73 0, // The delegated install prompt depends on what's being installed.
75 static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
76 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
77 0, // Inline installs use the extension name.
78 0, // Heading for bundle installs depends on the bundle contents.
79 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
80 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
81 0, // External installs use different strings for extensions/apps.
82 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
83 IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING,
84 IDS_EXTENSION_REMOTE_INSTALL_PROMPT_HEADING,
85 IDS_EXTENSION_REPAIR_PROMPT_HEADING,
86 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
88 static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
89 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
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_CANCEL,
96 ui::DIALOG_BUTTON_OK | 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,
101 static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
102 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
103 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
104 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
105 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
106 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
107 0, // External installs use different strings for extensions/apps.
108 0, // Different strings depending on the files and devices retained.
109 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON,
110 IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON,
111 IDS_EXTENSION_PROMPT_REPAIR_BUTTON,
112 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
114 static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
115 0, // These all use the platform's default cancel label.
119 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
120 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
121 IDS_CLOSE,
122 0, // Platform dependent cancel button.
125 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
127 static const int
128 kPermissionsHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
129 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
130 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
131 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
132 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
133 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
134 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
135 IDS_EXTENSION_PROMPT_CAN_ACCESS,
136 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
137 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
138 IDS_EXTENSION_PROMPT_CAN_ACCESS,
139 IDS_EXTENSION_PROMPT_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 (ExtensionInstallPrompt::g_auto_confirm_for_tests) {
156 case ExtensionInstallPrompt::NONE:
157 return false;
158 // We use PostTask instead of calling the delegate directly here, because in
159 // the real implementations it's highly likely the message loop will be
160 // pumping a few times before the user clicks accept or cancel.
161 case ExtensionInstallPrompt::ACCEPT:
162 base::MessageLoop::current()->PostTask(
163 FROM_HERE,
164 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
165 base::Unretained(delegate)));
166 return true;
167 case ExtensionInstallPrompt::CANCEL:
168 base::MessageLoop::current()->PostTask(
169 FROM_HERE,
170 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
171 base::Unretained(delegate),
172 true));
173 return true;
176 NOTREACHED();
177 return false;
180 Profile* ProfileForWebContents(content::WebContents* web_contents) {
181 if (!web_contents)
182 return NULL;
183 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
186 } // namespace
188 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
189 InstallPromptPermissions() {
191 ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
192 ~InstallPromptPermissions() {
195 // static
196 ExtensionInstallPrompt::AutoConfirmForTests
197 ExtensionInstallPrompt::g_auto_confirm_for_tests = ExtensionInstallPrompt::NONE;
199 ExtensionInstallPrompt::PromptType
200 ExtensionInstallPrompt::g_last_prompt_type_for_tests =
201 ExtensionInstallPrompt::UNSET_PROMPT_TYPE;
203 // This should match the PromptType enum.
204 std::string ExtensionInstallPrompt::PromptTypeToString(PromptType type) {
205 switch (type) {
206 case ExtensionInstallPrompt::INSTALL_PROMPT:
207 return "INSTALL_PROMPT";
208 case ExtensionInstallPrompt::INLINE_INSTALL_PROMPT:
209 return "INLINE_INSTALL_PROMPT";
210 case ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT:
211 return "BUNDLE_INSTALL_PROMPT";
212 case ExtensionInstallPrompt::RE_ENABLE_PROMPT:
213 return "RE_ENABLE_PROMPT";
214 case ExtensionInstallPrompt::PERMISSIONS_PROMPT:
215 return "PERMISSIONS_PROMPT";
216 case ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT:
217 return "EXTERNAL_INSTALL_PROMPT";
218 case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT:
219 return "POST_INSTALL_PERMISSIONS_PROMPT";
220 case ExtensionInstallPrompt::LAUNCH_PROMPT:
221 return "LAUNCH_PROMPT";
222 case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT:
223 return "REMOTE_INSTALL_PROMPT";
224 case ExtensionInstallPrompt::REPAIR_PROMPT:
225 return "REPAIR_PROMPT";
226 case ExtensionInstallPrompt::DELEGATED_PERMISSIONS_PROMPT:
227 return "DELEGATED_PERMISSIONS_PROMPT";
228 case ExtensionInstallPrompt::UNSET_PROMPT_TYPE:
229 case ExtensionInstallPrompt::NUM_PROMPT_TYPES:
230 break;
232 return "OTHER";
235 ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
236 : type_(type),
237 is_showing_details_for_retained_files_(false),
238 is_showing_details_for_retained_devices_(false),
239 extension_(NULL),
240 bundle_(NULL),
241 average_rating_(0.0),
242 rating_count_(0),
243 show_user_count_(false),
244 has_webstore_data_(false) {
247 ExtensionInstallPrompt::Prompt::~Prompt() {
250 void ExtensionInstallPrompt::Prompt::SetPermissions(
251 const std::vector<base::string16>& permissions,
252 PermissionsType permissions_type) {
253 GetPermissionsForType(permissions_type).permissions = permissions;
256 void ExtensionInstallPrompt::Prompt::SetPermissionsDetails(
257 const std::vector<base::string16>& details,
258 PermissionsType permissions_type) {
259 InstallPromptPermissions& install_permissions =
260 GetPermissionsForType(permissions_type);
262 // Add a dash to the front of each permission detail.
263 for (const auto& details_entry : details) {
264 if (!details_entry.empty()) {
265 std::vector<base::string16> detail_lines;
266 base::SplitString(details_entry, base::char16('\n'), &detail_lines);
268 std::vector<base::string16> detail_lines_with_bullets;
269 for (const auto& detail_line : detail_lines)
270 detail_lines_with_bullets.push_back(base::ASCIIToUTF16("- ") +
271 detail_line);
273 install_permissions.details.push_back(
274 JoinString(detail_lines_with_bullets, '\n'));
275 } else {
276 install_permissions.details.push_back(details_entry);
280 install_permissions.is_showing_details.clear();
281 install_permissions.is_showing_details.insert(
282 install_permissions.is_showing_details.begin(), details.size(), false);
285 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
286 DetailsType type,
287 size_t index,
288 bool is_showing_details) {
289 switch (type) {
290 case PERMISSIONS_DETAILS:
291 prompt_permissions_.is_showing_details[index] = is_showing_details;
292 break;
293 case WITHHELD_PERMISSIONS_DETAILS:
294 withheld_prompt_permissions_.is_showing_details[index] =
295 is_showing_details;
296 break;
297 case RETAINED_FILES_DETAILS:
298 is_showing_details_for_retained_files_ = is_showing_details;
299 break;
300 case RETAINED_DEVICES_DETAILS:
301 is_showing_details_for_retained_devices_ = is_showing_details;
302 break;
306 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
307 const std::string& localized_user_count,
308 bool show_user_count,
309 double average_rating,
310 int rating_count) {
311 CHECK(AllowWebstoreData(type_));
312 localized_user_count_ = localized_user_count;
313 show_user_count_ = show_user_count;
314 average_rating_ = average_rating;
315 rating_count_ = rating_count;
316 has_webstore_data_ = true;
319 base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
320 int resource_id = kTitleIds[type_];
322 if (type_ == INSTALL_PROMPT) {
323 if (extension_->is_app())
324 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
325 else if (extension_->is_theme())
326 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
327 else
328 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
329 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
330 return l10n_util::GetStringFUTF16(
331 resource_id, base::UTF8ToUTF16(extension_->name()));
332 } else if (type_ == REMOTE_INSTALL_PROMPT) {
333 if (extension_->is_app())
334 resource_id = IDS_EXTENSION_REMOTE_INSTALL_APP_PROMPT_TITLE;
335 else
336 resource_id = IDS_EXTENSION_REMOTE_INSTALL_EXTENSION_PROMPT_TITLE;
337 } else if (type_ == REPAIR_PROMPT) {
338 if (extension_->is_app())
339 resource_id = IDS_EXTENSION_REPAIR_APP_PROMPT_TITLE;
340 else
341 resource_id = IDS_EXTENSION_REPAIR_EXTENSION_PROMPT_TITLE;
342 } else if (type_ == DELEGATED_PERMISSIONS_PROMPT) {
343 DCHECK(!delegated_username_.empty());
344 if (extension_->is_app())
345 resource_id = IDS_EXTENSION_DELEGATED_INSTALL_APP_PROMPT_TITLE;
346 else
347 resource_id = IDS_EXTENSION_DELEGATED_INSTALL_EXTENSION_PROMPT_TITLE;
348 return l10n_util::GetStringFUTF16(
349 resource_id, base::UTF8ToUTF16(delegated_username_));
352 return l10n_util::GetStringUTF16(resource_id);
355 base::string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
356 if (type_ == INLINE_INSTALL_PROMPT) {
357 return base::UTF8ToUTF16(extension_->name());
358 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
359 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
360 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
361 int resource_id = -1;
362 if (extension_->is_app())
363 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
364 else if (extension_->is_theme())
365 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
366 else
367 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
368 return l10n_util::GetStringUTF16(resource_id);
369 } else {
370 return l10n_util::GetStringFUTF16(
371 kHeadingIds[type_], base::UTF8ToUTF16(extension_->name()));
375 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
376 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT && ShouldDisplayRevokeButton()) {
377 return kButtons[type_] | ui::DIALOG_BUTTON_OK;
380 return kButtons[type_];
383 bool ExtensionInstallPrompt::Prompt::ShouldShowExplanationText() const {
384 return type_ == INSTALL_PROMPT && extension_->is_extension() &&
385 experiment_.get() && experiment_->text_only();
388 bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
389 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT)
390 return ShouldDisplayRevokeButton();
392 if (kAcceptButtonIds[type_] == 0)
393 return false;
395 return true;
398 base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
399 if (type_ == EXTERNAL_INSTALL_PROMPT) {
400 int id = -1;
401 if (extension_->is_app())
402 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
403 else if (extension_->is_theme())
404 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
405 else
406 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
407 return l10n_util::GetStringUTF16(id);
408 } else if (type_ == POST_INSTALL_PERMISSIONS_PROMPT) {
409 int id = -1;
410 if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
411 id =
412 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON;
413 } else if (GetRetainedFileCount()) {
414 id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON;
415 } else {
416 DCHECK_LT(0U, GetRetainedDeviceCount());
417 id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON;
419 return l10n_util::GetStringUTF16(id);
421 if (ShouldShowExplanationText())
422 return experiment_->GetOkButtonText();
423 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
426 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
427 if (ShouldShowExplanationText())
428 return true;
429 return kAbortButtonIds[type_] > 0;
432 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
433 CHECK(HasAbortButtonLabel());
434 if (ShouldShowExplanationText())
435 return experiment_->GetCancelButtonText();
436 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
439 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
440 PermissionsType permissions_type) const {
441 switch (permissions_type) {
442 case REGULAR_PERMISSIONS:
443 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
444 case WITHHELD_PERMISSIONS:
445 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD);
446 case ALL_PERMISSIONS:
447 default:
448 NOTREACHED();
449 return base::string16();
453 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
454 const int kRetainedFilesMessageIDs[6] = {
455 IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT,
456 IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR,
457 IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO,
458 IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO,
459 IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW,
460 IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY,
462 std::vector<int> message_ids(
463 kRetainedFilesMessageIDs,
464 kRetainedFilesMessageIDs + arraysize(kRetainedFilesMessageIDs));
466 return l10n_util::GetPluralStringFUTF16(message_ids, GetRetainedFileCount());
469 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedDevicesHeading()
470 const {
471 const int kRetainedDevicesMessageIDs[6] = {
472 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_DEFAULT,
473 IDS_EXTENSION_PROMPT_RETAINED_DEVICE_SINGULAR,
474 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_ZERO,
475 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_TWO,
476 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_FEW,
477 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_MANY,
479 std::vector<int> message_ids(
480 kRetainedDevicesMessageIDs,
481 kRetainedDevicesMessageIDs + arraysize(kRetainedDevicesMessageIDs));
483 return l10n_util::GetPluralStringFUTF16(message_ids,
484 GetRetainedDeviceCount());
487 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
488 return GetPermissionCount(ALL_PERMISSIONS) > 0 ||
489 type_ == POST_INSTALL_PERMISSIONS_PROMPT;
492 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
493 StarAppender appender, void* data) const {
494 CHECK(appender);
495 CHECK(AllowWebstoreData(type_));
496 int rating_integer = floor(average_rating_);
497 double rating_fractional = average_rating_ - rating_integer;
499 if (rating_fractional > 0.66) {
500 rating_integer++;
503 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
504 rating_fractional = 0;
507 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
508 int i;
509 for (i = 0; i < rating_integer; i++) {
510 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
512 if (rating_fractional) {
513 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
514 i++;
516 for (; i < kMaxExtensionRating; i++) {
517 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
521 base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
522 CHECK(AllowWebstoreData(type_));
523 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
524 base::IntToString16(rating_count_));
527 base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
528 CHECK(AllowWebstoreData(type_));
530 if (show_user_count_) {
531 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
532 base::UTF8ToUTF16(localized_user_count_));
534 return base::string16();
537 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount(
538 PermissionsType permissions_type) const {
539 switch (permissions_type) {
540 case REGULAR_PERMISSIONS:
541 return prompt_permissions_.permissions.size();
542 case WITHHELD_PERMISSIONS:
543 return withheld_prompt_permissions_.permissions.size();
544 case ALL_PERMISSIONS:
545 return prompt_permissions_.permissions.size() +
546 withheld_prompt_permissions_.permissions.size();
547 default:
548 NOTREACHED();
549 return 0u;
553 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount(
554 PermissionsType permissions_type) const {
555 switch (permissions_type) {
556 case REGULAR_PERMISSIONS:
557 return prompt_permissions_.details.size();
558 case WITHHELD_PERMISSIONS:
559 return withheld_prompt_permissions_.details.size();
560 case ALL_PERMISSIONS:
561 return prompt_permissions_.details.size() +
562 withheld_prompt_permissions_.details.size();
563 default:
564 NOTREACHED();
565 return 0u;
569 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(
570 size_t index,
571 PermissionsType permissions_type) const {
572 const InstallPromptPermissions& install_permissions =
573 GetPermissionsForType(permissions_type);
574 CHECK_LT(index, install_permissions.permissions.size());
575 return install_permissions.permissions[index];
578 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
579 size_t index,
580 PermissionsType permissions_type) const {
581 const InstallPromptPermissions& install_permissions =
582 GetPermissionsForType(permissions_type);
583 CHECK_LT(index, install_permissions.details.size());
584 return install_permissions.details[index];
587 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
588 DetailsType type, size_t index) const {
589 switch (type) {
590 case PERMISSIONS_DETAILS:
591 CHECK_LT(index, prompt_permissions_.is_showing_details.size());
592 return prompt_permissions_.is_showing_details[index];
593 case WITHHELD_PERMISSIONS_DETAILS:
594 CHECK_LT(index, withheld_prompt_permissions_.is_showing_details.size());
595 return withheld_prompt_permissions_.is_showing_details[index];
596 case RETAINED_FILES_DETAILS:
597 return is_showing_details_for_retained_files_;
598 case RETAINED_DEVICES_DETAILS:
599 return is_showing_details_for_retained_devices_;
601 return false;
604 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
605 return retained_files_.size();
608 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
609 const {
610 CHECK_LT(index, retained_files_.size());
611 return retained_files_[index].AsUTF16Unsafe();
614 size_t ExtensionInstallPrompt::Prompt::GetRetainedDeviceCount() const {
615 return retained_device_messages_.size();
618 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedDeviceMessageString(
619 size_t index) const {
620 CHECK_LT(index, retained_device_messages_.size());
621 return retained_device_messages_[index];
624 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeButton() const {
625 return !retained_files_.empty() || !retained_device_messages_.empty();
628 ExtensionInstallPrompt::Prompt::InstallPromptPermissions&
629 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
630 PermissionsType permissions_type) {
631 DCHECK_NE(ALL_PERMISSIONS, permissions_type);
632 return permissions_type == REGULAR_PERMISSIONS ? prompt_permissions_
633 : withheld_prompt_permissions_;
636 const ExtensionInstallPrompt::Prompt::InstallPromptPermissions&
637 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
638 PermissionsType permissions_type) const {
639 DCHECK_NE(ALL_PERMISSIONS, permissions_type);
640 return permissions_type == REGULAR_PERMISSIONS ? prompt_permissions_
641 : withheld_prompt_permissions_;
644 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
645 return !retained_files_.empty();
648 // static
649 scoped_refptr<Extension>
650 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
651 const base::DictionaryValue* manifest,
652 int flags,
653 const std::string& id,
654 const std::string& localized_name,
655 const std::string& localized_description,
656 std::string* error) {
657 scoped_ptr<base::DictionaryValue> localized_manifest;
658 if (!localized_name.empty() || !localized_description.empty()) {
659 localized_manifest.reset(manifest->DeepCopy());
660 if (!localized_name.empty()) {
661 localized_manifest->SetString(extensions::manifest_keys::kName,
662 localized_name);
664 if (!localized_description.empty()) {
665 localized_manifest->SetString(extensions::manifest_keys::kDescription,
666 localized_description);
670 return Extension::Create(
671 base::FilePath(),
672 Manifest::INTERNAL,
673 localized_manifest.get() ? *localized_manifest.get() : *manifest,
674 flags,
676 error);
679 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents)
680 : profile_(ProfileForWebContents(contents)),
681 ui_loop_(base::MessageLoop::current()),
682 extension_(NULL),
683 bundle_(NULL),
684 install_ui_(extensions::CreateExtensionInstallUI(
685 ProfileForWebContents(contents))),
686 show_params_(new ExtensionInstallPromptShowParams(contents)),
687 delegate_(NULL) {
690 ExtensionInstallPrompt::ExtensionInstallPrompt(Profile* profile,
691 gfx::NativeWindow native_window)
692 : profile_(profile),
693 ui_loop_(base::MessageLoop::current()),
694 extension_(NULL),
695 bundle_(NULL),
696 install_ui_(extensions::CreateExtensionInstallUI(profile)),
697 show_params_(
698 new ExtensionInstallPromptShowParams(profile, native_window)),
699 delegate_(NULL) {
702 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
705 void ExtensionInstallPrompt::ConfirmBundleInstall(
706 extensions::BundleInstaller* bundle,
707 const PermissionSet* permissions) {
708 DCHECK(ui_loop_ == base::MessageLoop::current());
709 bundle_ = bundle;
710 custom_permissions_ = permissions;
711 delegate_ = bundle;
712 prompt_ = new Prompt(BUNDLE_INSTALL_PROMPT);
714 ShowConfirmation();
717 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
718 Delegate* delegate,
719 const Extension* extension,
720 SkBitmap* icon,
721 scoped_refptr<Prompt> prompt) {
722 DCHECK(ui_loop_ == base::MessageLoop::current());
723 extension_ = extension;
724 delegate_ = delegate;
725 prompt_ = prompt;
727 SetIcon(icon);
728 ShowConfirmation();
731 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
732 Delegate* delegate,
733 const Extension* extension,
734 const SkBitmap* icon,
735 const ShowDialogCallback& show_dialog_callback) {
736 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
737 // remaining fields.
738 extension_ = extension;
739 SetIcon(icon);
740 ConfirmInstall(delegate, extension, show_dialog_callback);
743 void ExtensionInstallPrompt::ConfirmInstall(
744 Delegate* delegate,
745 const Extension* extension,
746 const ShowDialogCallback& show_dialog_callback) {
747 DCHECK(ui_loop_ == base::MessageLoop::current());
748 extension_ = extension;
749 delegate_ = delegate;
750 prompt_ = new Prompt(INSTALL_PROMPT);
751 show_dialog_callback_ = show_dialog_callback;
753 // We special-case themes to not show any confirm UI. Instead they are
754 // immediately installed, and then we show an infobar (see OnInstallSuccess)
755 // to allow the user to revert if they don't like it.
757 // We don't do this in the case where off-store extension installs are
758 // disabled because in that case, we don't show the dangerous download UI, so
759 // we need the UI confirmation.
760 if (extension->is_theme()) {
761 if (extension->from_webstore() ||
762 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
763 delegate->InstallUIProceed();
764 return;
768 LoadImageIfNeeded();
771 void ExtensionInstallPrompt::ConfirmPermissionsForDelegatedInstall(
772 Delegate* delegate,
773 const Extension* extension,
774 const std::string& delegated_username,
775 const SkBitmap* icon) {
776 DCHECK(ui_loop_ == base::MessageLoop::current());
777 delegate_ = delegate;
778 extension_ = extension;
779 delegated_username_ = delegated_username;
780 SetIcon(icon);
781 prompt_ = new Prompt(DELEGATED_PERMISSIONS_PROMPT);
782 ShowConfirmation();
785 void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
786 const Extension* extension) {
787 DCHECK(ui_loop_ == base::MessageLoop::current());
788 extension_ = extension;
789 delegate_ = delegate;
790 bool is_remote_install =
791 profile_ &&
792 extensions::ExtensionPrefs::Get(profile_)->HasDisableReason(
793 extension->id(), extensions::Extension::DISABLE_REMOTE_INSTALL);
794 bool is_ephemeral =
795 extensions::util::IsEphemeralApp(extension->id(), profile_);
797 PromptType type = UNSET_PROMPT_TYPE;
798 if (is_ephemeral)
799 type = LAUNCH_PROMPT;
800 else if (is_remote_install)
801 type = REMOTE_INSTALL_PROMPT;
802 else
803 type = RE_ENABLE_PROMPT;
804 prompt_ = new Prompt(type);
806 LoadImageIfNeeded();
809 void ExtensionInstallPrompt::ConfirmExternalInstall(
810 Delegate* delegate,
811 const Extension* extension,
812 const ShowDialogCallback& show_dialog_callback,
813 scoped_refptr<Prompt> prompt) {
814 DCHECK(ui_loop_ == base::MessageLoop::current());
815 extension_ = extension;
816 delegate_ = delegate;
817 prompt_ = prompt;
818 show_dialog_callback_ = show_dialog_callback;
820 LoadImageIfNeeded();
823 void ExtensionInstallPrompt::ConfirmPermissions(
824 Delegate* delegate,
825 const Extension* extension,
826 const PermissionSet* permissions) {
827 DCHECK(ui_loop_ == base::MessageLoop::current());
828 extension_ = extension;
829 custom_permissions_ = permissions;
830 delegate_ = delegate;
831 prompt_ = new Prompt(PERMISSIONS_PROMPT);
833 LoadImageIfNeeded();
836 void ExtensionInstallPrompt::ReviewPermissions(
837 Delegate* delegate,
838 const Extension* extension,
839 const std::vector<base::FilePath>& retained_file_paths,
840 const std::vector<base::string16>& retained_device_messages) {
841 DCHECK(ui_loop_ == base::MessageLoop::current());
842 extension_ = extension;
843 prompt_ = new Prompt(POST_INSTALL_PERMISSIONS_PROMPT);
844 prompt_->set_retained_files(retained_file_paths);
845 prompt_->set_retained_device_messages(retained_device_messages);
846 delegate_ = delegate;
848 LoadImageIfNeeded();
851 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
852 SkBitmap* icon) {
853 extension_ = extension;
854 SetIcon(icon);
856 install_ui_->OnInstallSuccess(extension, &icon_);
859 void ExtensionInstallPrompt::OnInstallFailure(
860 const extensions::CrxInstallError& error) {
861 install_ui_->OnInstallFailure(error);
864 void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
865 if (image)
866 icon_ = *image;
867 else
868 icon_ = SkBitmap();
869 if (icon_.empty()) {
870 // Let's set default icon bitmap whose size is equal to the default icon's
871 // pixel size under maximal supported scale factor. If the bitmap is larger
872 // than the one we need, it will be scaled down by the ui code.
873 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
877 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
878 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
879 ShowConfirmation();
882 void ExtensionInstallPrompt::LoadImageIfNeeded() {
883 // Bundle install prompts do not have an icon.
884 // Also |profile_| can be NULL in unit tests.
885 if (!icon_.empty() || !profile_) {
886 ShowConfirmation();
887 return;
890 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
891 extension_,
892 extension_misc::EXTENSION_ICON_LARGE,
893 ExtensionIconSet::MATCH_BIGGER);
895 // Load the image asynchronously. The response will be sent to OnImageLoaded.
896 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile_);
898 std::vector<extensions::ImageLoader::ImageRepresentation> images_list;
899 images_list.push_back(extensions::ImageLoader::ImageRepresentation(
900 image,
901 extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE,
902 gfx::Size(),
903 ui::SCALE_FACTOR_100P));
904 loader->LoadImagesAsync(
905 extension_,
906 images_list,
907 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
910 void ExtensionInstallPrompt::ShowConfirmation() {
911 if (prompt_->type() == INSTALL_PROMPT)
912 prompt_->set_experiment(ExtensionInstallPromptExperiment::Find());
913 else
914 prompt_->set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
916 scoped_refptr<const PermissionSet> permissions_to_display;
917 if (custom_permissions_.get()) {
918 permissions_to_display = custom_permissions_;
919 } else if (extension_) {
920 // Initialize permissions if they have not already been set so that
921 // withheld permissions are displayed properly in the install prompt.
922 extensions::PermissionsUpdater(
923 profile_, extensions::PermissionsUpdater::INIT_FLAG_TRANSIENT)
924 .InitializePermissions(extension_);
925 permissions_to_display =
926 extension_->permissions_data()->active_permissions();
929 if (permissions_to_display.get() &&
930 (!extension_ ||
931 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
932 extension_->id()))) {
933 Manifest::Type type =
934 extension_ ? extension_->GetType() : Manifest::TYPE_UNKNOWN;
935 const extensions::PermissionMessageProvider* message_provider =
936 extensions::PermissionMessageProvider::Get();
937 prompt_->SetPermissions(message_provider->GetWarningMessages(
938 permissions_to_display.get(), type),
939 REGULAR_PERMISSIONS);
940 prompt_->SetPermissionsDetails(message_provider->GetWarningMessagesDetails(
941 permissions_to_display.get(), type),
942 REGULAR_PERMISSIONS);
944 scoped_refptr<const extensions::PermissionSet> withheld =
945 extension_->permissions_data()->withheld_permissions();
946 if (!withheld->IsEmpty()) {
947 prompt_->SetPermissions(
948 message_provider->GetWarningMessages(withheld.get(), type),
949 PermissionsType::WITHHELD_PERMISSIONS);
950 prompt_->SetPermissionsDetails(
951 message_provider->GetWarningMessagesDetails(withheld.get(), type),
952 PermissionsType::WITHHELD_PERMISSIONS);
956 switch (prompt_->type()) {
957 case PERMISSIONS_PROMPT:
958 case RE_ENABLE_PROMPT:
959 case INLINE_INSTALL_PROMPT:
960 case EXTERNAL_INSTALL_PROMPT:
961 case INSTALL_PROMPT:
962 case LAUNCH_PROMPT:
963 case POST_INSTALL_PERMISSIONS_PROMPT:
964 case REMOTE_INSTALL_PROMPT:
965 case REPAIR_PROMPT:
966 case DELEGATED_PERMISSIONS_PROMPT: {
967 prompt_->set_extension(extension_);
968 prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
969 prompt_->set_delegated_username(delegated_username_);
970 break;
972 case BUNDLE_INSTALL_PROMPT: {
973 prompt_->set_bundle(bundle_);
974 break;
976 default:
977 NOTREACHED() << "Unknown message";
978 return;
981 g_last_prompt_type_for_tests = prompt_->type();
983 if (AutoConfirmPrompt(delegate_))
984 return;
986 if (show_params_->WasParentDestroyed()) {
987 delegate_->InstallUIAbort(false);
988 return;
991 if (show_dialog_callback_.is_null())
992 GetDefaultShowDialogCallback().Run(show_params_.get(), delegate_, prompt_);
993 else
994 show_dialog_callback_.Run(show_params_.get(), delegate_, prompt_);