MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / browser / extensions / extension_install_prompt.cc
blobd692d9ee362f6e224627edc1c4c60ccd60201851
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_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/extensions/bundle_installer.h"
17 #include "chrome/browser/extensions/extension_util.h"
18 #include "chrome/browser/extensions/permissions_updater.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/extensions/extension_install_ui_factory.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/grit/chromium_strings.h"
24 #include "chrome/grit/generated_resources.h"
25 #include "content/public/browser/web_contents.h"
26 #include "extensions/browser/extension_prefs.h"
27 #include "extensions/browser/extension_util.h"
28 #include "extensions/browser/image_loader.h"
29 #include "extensions/browser/install/extension_install_ui.h"
30 #include "extensions/common/constants.h"
31 #include "extensions/common/extension.h"
32 #include "extensions/common/extension_icon_set.h"
33 #include "extensions/common/extension_resource.h"
34 #include "extensions/common/feature_switch.h"
35 #include "extensions/common/manifest.h"
36 #include "extensions/common/manifest_constants.h"
37 #include "extensions/common/manifest_handlers/icons_handler.h"
38 #include "extensions/common/permissions/permission_message_provider.h"
39 #include "extensions/common/permissions/permission_set.h"
40 #include "extensions/common/permissions/permissions_data.h"
41 #include "extensions/common/url_pattern.h"
42 #include "grit/theme_resources.h"
43 #include "ui/base/l10n/l10n_util.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/base/ui_base_types.h"
46 #include "ui/gfx/image/image.h"
48 using extensions::BundleInstaller;
49 using extensions::Extension;
50 using extensions::Manifest;
51 using extensions::PermissionSet;
53 namespace {
55 bool AllowWebstoreData(ExtensionInstallPrompt::PromptType type) {
56 return type == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT ||
57 type == ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT ||
58 type == ExtensionInstallPrompt::REPAIR_PROMPT;
61 static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
62 0, // The regular install prompt depends on what's being installed.
63 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
64 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
65 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
66 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
67 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
68 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
69 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE,
70 0, // The remote install prompt depends on what's being installed.
71 0, // The repair install prompt depends on what's being installed.
73 static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
74 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
75 0, // Inline installs use the extension name.
76 0, // Heading for bundle installs depends on the bundle contents.
77 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
78 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
79 0, // External installs use different strings for extensions/apps.
80 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
81 IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING,
82 IDS_EXTENSION_REMOTE_INSTALL_PROMPT_HEADING,
83 IDS_EXTENSION_REPAIR_PROMPT_HEADING
85 static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
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,
90 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
91 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
92 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,
97 static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
98 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
99 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
100 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
101 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
102 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
103 0, // External installs use different strings for extensions/apps.
104 0, // Different strings depending on the files and devices retained.
105 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON,
106 IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON,
107 IDS_EXTENSION_PROMPT_REPAIR_BUTTON,
109 static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
110 0, // These all use the platform's default cancel label.
114 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
115 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
116 IDS_CLOSE,
117 0, // Platform dependent cancel button.
121 static const int
122 kPermissionsHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
123 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
124 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
125 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
126 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
127 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
128 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
129 IDS_EXTENSION_PROMPT_CAN_ACCESS,
130 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
131 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
132 IDS_EXTENSION_PROMPT_CAN_ACCESS,
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 (ExtensionInstallPrompt::g_auto_confirm_for_tests) {
149 case ExtensionInstallPrompt::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 ExtensionInstallPrompt::ACCEPT:
155 base::MessageLoop::current()->PostTask(
156 FROM_HERE,
157 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
158 base::Unretained(delegate)));
159 return true;
160 case ExtensionInstallPrompt::CANCEL:
161 base::MessageLoop::current()->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 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
180 if (!contents)
181 return NULL;
183 return contents->GetTopLevelNativeWindow();
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 // This should match the PromptType enum.
200 std::string ExtensionInstallPrompt::PromptTypeToString(PromptType type) {
201 switch (type) {
202 case ExtensionInstallPrompt::INSTALL_PROMPT:
203 return "INSTALL_PROMPT";
204 case ExtensionInstallPrompt::INLINE_INSTALL_PROMPT:
205 return "INLINE_INSTALL_PROMPT";
206 case ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT:
207 return "BUNDLE_INSTALL_PROMPT";
208 case ExtensionInstallPrompt::RE_ENABLE_PROMPT:
209 return "RE_ENABLE_PROMPT";
210 case ExtensionInstallPrompt::PERMISSIONS_PROMPT:
211 return "PERMISSIONS_PROMPT";
212 case ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT:
213 return "EXTERNAL_INSTALL_PROMPT";
214 case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT:
215 return "POST_INSTALL_PERMISSIONS_PROMPT";
216 case ExtensionInstallPrompt::LAUNCH_PROMPT:
217 return "LAUNCH_PROMPT";
218 case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT:
219 return "REMOTE_INSTALL_PROMPT";
220 case ExtensionInstallPrompt::REPAIR_PROMPT:
221 return "REPAIR_PROMPT";
222 case ExtensionInstallPrompt::UNSET_PROMPT_TYPE:
223 case ExtensionInstallPrompt::NUM_PROMPT_TYPES:
224 break;
226 return "OTHER";
229 ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
230 : type_(type),
231 is_showing_details_for_retained_files_(false),
232 is_showing_details_for_retained_devices_(false),
233 extension_(NULL),
234 bundle_(NULL),
235 average_rating_(0.0),
236 rating_count_(0),
237 show_user_count_(false),
238 has_webstore_data_(false) {
241 ExtensionInstallPrompt::Prompt::~Prompt() {
244 void ExtensionInstallPrompt::Prompt::SetPermissions(
245 const std::vector<base::string16>& permissions,
246 PermissionsType permissions_type) {
247 GetPermissionsForType(permissions_type).permissions = permissions;
250 void ExtensionInstallPrompt::Prompt::SetPermissionsDetails(
251 const std::vector<base::string16>& details,
252 PermissionsType permissions_type) {
253 InstallPromptPermissions& install_permissions =
254 GetPermissionsForType(permissions_type);
255 install_permissions.details = details;
256 install_permissions.is_showing_details.clear();
257 install_permissions.is_showing_details.insert(
258 install_permissions.is_showing_details.begin(), details.size(), false);
261 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
262 DetailsType type,
263 size_t index,
264 bool is_showing_details) {
265 switch (type) {
266 case PERMISSIONS_DETAILS:
267 prompt_permissions_.is_showing_details[index] = is_showing_details;
268 break;
269 case WITHHELD_PERMISSIONS_DETAILS:
270 withheld_prompt_permissions_.is_showing_details[index] =
271 is_showing_details;
272 break;
273 case RETAINED_FILES_DETAILS:
274 is_showing_details_for_retained_files_ = is_showing_details;
275 break;
276 case RETAINED_DEVICES_DETAILS:
277 is_showing_details_for_retained_devices_ = is_showing_details;
278 break;
282 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
283 const std::string& localized_user_count,
284 bool show_user_count,
285 double average_rating,
286 int rating_count) {
287 CHECK(AllowWebstoreData(type_));
288 localized_user_count_ = localized_user_count;
289 show_user_count_ = show_user_count;
290 average_rating_ = average_rating;
291 rating_count_ = rating_count;
292 has_webstore_data_ = true;
295 base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
296 int resource_id = kTitleIds[type_];
298 if (type_ == INSTALL_PROMPT) {
299 if (extension_->is_app())
300 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
301 else if (extension_->is_theme())
302 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
303 else
304 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
305 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
306 return l10n_util::GetStringFUTF16(
307 resource_id, base::UTF8ToUTF16(extension_->name()));
308 } else if (type_ == REMOTE_INSTALL_PROMPT) {
309 if (extension_->is_app())
310 resource_id = IDS_EXTENSION_REMOTE_INSTALL_APP_PROMPT_TITLE;
311 else
312 resource_id = IDS_EXTENSION_REMOTE_INSTALL_EXTENSION_PROMPT_TITLE;
313 } else if (type_ == REPAIR_PROMPT) {
314 if (extension_->is_app())
315 resource_id = IDS_EXTENSION_REPAIR_APP_PROMPT_TITLE;
316 else
317 resource_id = IDS_EXTENSION_REPAIR_EXTENSION_PROMPT_TITLE;
320 return l10n_util::GetStringUTF16(resource_id);
323 base::string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
324 if (type_ == INLINE_INSTALL_PROMPT) {
325 return base::UTF8ToUTF16(extension_->name());
326 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
327 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
328 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
329 int resource_id = -1;
330 if (extension_->is_app())
331 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
332 else if (extension_->is_theme())
333 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
334 else
335 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
336 return l10n_util::GetStringUTF16(resource_id);
337 } else {
338 return l10n_util::GetStringFUTF16(
339 kHeadingIds[type_], base::UTF8ToUTF16(extension_->name()));
343 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
344 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT && ShouldDisplayRevokeButton()) {
345 return kButtons[type_] | ui::DIALOG_BUTTON_OK;
348 return kButtons[type_];
351 bool ExtensionInstallPrompt::Prompt::ShouldShowExplanationText() const {
352 return type_ == INSTALL_PROMPT && extension_->is_extension() &&
353 experiment_.get() && experiment_->text_only();
356 bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
357 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT)
358 return ShouldDisplayRevokeButton();
360 if (kAcceptButtonIds[type_] == 0)
361 return false;
363 return true;
366 base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
367 if (type_ == EXTERNAL_INSTALL_PROMPT) {
368 int id = -1;
369 if (extension_->is_app())
370 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
371 else if (extension_->is_theme())
372 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
373 else
374 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
375 return l10n_util::GetStringUTF16(id);
376 } else if (type_ == POST_INSTALL_PERMISSIONS_PROMPT) {
377 int id = -1;
378 if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
379 id =
380 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON;
381 } else if (GetRetainedFileCount()) {
382 id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON;
383 } else {
384 DCHECK_LT(0U, GetRetainedDeviceCount());
385 id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON;
387 return l10n_util::GetStringUTF16(id);
389 if (ShouldShowExplanationText())
390 return experiment_->GetOkButtonText();
391 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
394 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
395 if (ShouldShowExplanationText())
396 return true;
397 return kAbortButtonIds[type_] > 0;
400 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
401 CHECK(HasAbortButtonLabel());
402 if (ShouldShowExplanationText())
403 return experiment_->GetCancelButtonText();
404 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
407 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
408 PermissionsType permissions_type) const {
409 switch (permissions_type) {
410 case REGULAR_PERMISSIONS:
411 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
412 case WITHHELD_PERMISSIONS:
413 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD);
414 case ALL_PERMISSIONS:
415 default:
416 NOTREACHED();
417 return base::string16();
421 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
422 const int kRetainedFilesMessageIDs[6] = {
423 IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT,
424 IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR,
425 IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO,
426 IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO,
427 IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW,
428 IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY,
430 std::vector<int> message_ids(
431 kRetainedFilesMessageIDs,
432 kRetainedFilesMessageIDs + arraysize(kRetainedFilesMessageIDs));
434 return l10n_util::GetPluralStringFUTF16(message_ids, GetRetainedFileCount());
437 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedDevicesHeading()
438 const {
439 const int kRetainedDevicesMessageIDs[6] = {
440 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_DEFAULT,
441 IDS_EXTENSION_PROMPT_RETAINED_DEVICE_SINGULAR,
442 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_ZERO,
443 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_TWO,
444 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_FEW,
445 IDS_EXTENSION_PROMPT_RETAINED_DEVICES_MANY,
447 std::vector<int> message_ids(
448 kRetainedDevicesMessageIDs,
449 kRetainedDevicesMessageIDs + arraysize(kRetainedDevicesMessageIDs));
451 return l10n_util::GetPluralStringFUTF16(message_ids,
452 GetRetainedDeviceCount());
455 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
456 return GetPermissionCount(ALL_PERMISSIONS) > 0 ||
457 type_ == POST_INSTALL_PERMISSIONS_PROMPT;
460 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
461 StarAppender appender, void* data) const {
462 CHECK(appender);
463 CHECK(AllowWebstoreData(type_));
464 int rating_integer = floor(average_rating_);
465 double rating_fractional = average_rating_ - rating_integer;
467 if (rating_fractional > 0.66) {
468 rating_integer++;
471 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
472 rating_fractional = 0;
475 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
476 int i;
477 for (i = 0; i < rating_integer; i++) {
478 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
480 if (rating_fractional) {
481 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
482 i++;
484 for (; i < kMaxExtensionRating; i++) {
485 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
489 base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
490 CHECK(AllowWebstoreData(type_));
491 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
492 base::IntToString16(rating_count_));
495 base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
496 CHECK(AllowWebstoreData(type_));
498 if (show_user_count_) {
499 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
500 base::UTF8ToUTF16(localized_user_count_));
502 return base::string16();
505 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount(
506 PermissionsType permissions_type) const {
507 switch (permissions_type) {
508 case REGULAR_PERMISSIONS:
509 return prompt_permissions_.permissions.size();
510 case WITHHELD_PERMISSIONS:
511 return withheld_prompt_permissions_.permissions.size();
512 case ALL_PERMISSIONS:
513 return prompt_permissions_.permissions.size() +
514 withheld_prompt_permissions_.permissions.size();
515 default:
516 NOTREACHED();
517 return 0u;
521 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount(
522 PermissionsType permissions_type) const {
523 switch (permissions_type) {
524 case REGULAR_PERMISSIONS:
525 return prompt_permissions_.details.size();
526 case WITHHELD_PERMISSIONS:
527 return withheld_prompt_permissions_.details.size();
528 case ALL_PERMISSIONS:
529 return prompt_permissions_.details.size() +
530 withheld_prompt_permissions_.details.size();
531 default:
532 NOTREACHED();
533 return 0u;
537 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(
538 size_t index,
539 PermissionsType permissions_type) const {
540 const InstallPromptPermissions& install_permissions =
541 GetPermissionsForType(permissions_type);
542 CHECK_LT(index, install_permissions.permissions.size());
543 return install_permissions.permissions[index];
546 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
547 size_t index,
548 PermissionsType permissions_type) const {
549 const InstallPromptPermissions& install_permissions =
550 GetPermissionsForType(permissions_type);
551 CHECK_LT(index, install_permissions.details.size());
552 return install_permissions.details[index];
555 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
556 DetailsType type, size_t index) const {
557 switch (type) {
558 case PERMISSIONS_DETAILS:
559 CHECK_LT(index, prompt_permissions_.is_showing_details.size());
560 return prompt_permissions_.is_showing_details[index];
561 case WITHHELD_PERMISSIONS_DETAILS:
562 CHECK_LT(index, withheld_prompt_permissions_.is_showing_details.size());
563 return withheld_prompt_permissions_.is_showing_details[index];
564 case RETAINED_FILES_DETAILS:
565 return is_showing_details_for_retained_files_;
566 case RETAINED_DEVICES_DETAILS:
567 return is_showing_details_for_retained_devices_;
569 return false;
572 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
573 return retained_files_.size();
576 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
577 const {
578 CHECK_LT(index, retained_files_.size());
579 return retained_files_[index].AsUTF16Unsafe();
582 size_t ExtensionInstallPrompt::Prompt::GetRetainedDeviceCount() const {
583 return retained_device_messages_.size();
586 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedDeviceMessageString(
587 size_t index) const {
588 CHECK_LT(index, retained_device_messages_.size());
589 return retained_device_messages_[index];
592 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeButton() const {
593 return !retained_files_.empty() || !retained_device_messages_.empty();
596 ExtensionInstallPrompt::Prompt::InstallPromptPermissions&
597 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
598 PermissionsType permissions_type) {
599 DCHECK_NE(ALL_PERMISSIONS, permissions_type);
600 return permissions_type == REGULAR_PERMISSIONS ? prompt_permissions_
601 : withheld_prompt_permissions_;
604 const ExtensionInstallPrompt::Prompt::InstallPromptPermissions&
605 ExtensionInstallPrompt::Prompt::GetPermissionsForType(
606 PermissionsType permissions_type) const {
607 DCHECK_NE(ALL_PERMISSIONS, permissions_type);
608 return permissions_type == REGULAR_PERMISSIONS ? prompt_permissions_
609 : withheld_prompt_permissions_;
612 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
613 return !retained_files_.empty();
616 ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
617 : profile(ProfileForWebContents(contents)),
618 parent_web_contents(contents),
619 parent_window(NativeWindowForWebContents(contents)) {
622 ExtensionInstallPrompt::ShowParams::ShowParams(Profile* profile,
623 gfx::NativeWindow window)
624 : profile(profile),
625 parent_web_contents(NULL),
626 parent_window(window) {
629 // static
630 scoped_refptr<Extension>
631 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
632 const base::DictionaryValue* manifest,
633 int flags,
634 const std::string& id,
635 const std::string& localized_name,
636 const std::string& localized_description,
637 std::string* error) {
638 scoped_ptr<base::DictionaryValue> localized_manifest;
639 if (!localized_name.empty() || !localized_description.empty()) {
640 localized_manifest.reset(manifest->DeepCopy());
641 if (!localized_name.empty()) {
642 localized_manifest->SetString(extensions::manifest_keys::kName,
643 localized_name);
645 if (!localized_description.empty()) {
646 localized_manifest->SetString(extensions::manifest_keys::kDescription,
647 localized_description);
651 return Extension::Create(
652 base::FilePath(),
653 Manifest::INTERNAL,
654 localized_manifest.get() ? *localized_manifest.get() : *manifest,
655 flags,
657 error);
660 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents)
661 : profile_(ProfileForWebContents(contents)),
662 ui_loop_(base::MessageLoop::current()),
663 extension_(NULL),
664 bundle_(NULL),
665 install_ui_(extensions::CreateExtensionInstallUI(
666 ProfileForWebContents(contents))),
667 show_params_(contents),
668 delegate_(NULL) {
671 ExtensionInstallPrompt::ExtensionInstallPrompt(Profile* profile,
672 gfx::NativeWindow native_window)
673 : profile_(profile),
674 ui_loop_(base::MessageLoop::current()),
675 extension_(NULL),
676 bundle_(NULL),
677 install_ui_(extensions::CreateExtensionInstallUI(profile)),
678 show_params_(profile, native_window),
679 delegate_(NULL) {
682 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
685 void ExtensionInstallPrompt::ConfirmBundleInstall(
686 extensions::BundleInstaller* bundle,
687 const PermissionSet* permissions) {
688 DCHECK(ui_loop_ == base::MessageLoop::current());
689 bundle_ = bundle;
690 custom_permissions_ = permissions;
691 delegate_ = bundle;
692 prompt_ = new Prompt(BUNDLE_INSTALL_PROMPT);
694 ShowConfirmation();
697 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
698 Delegate* delegate,
699 const Extension* extension,
700 SkBitmap* icon,
701 scoped_refptr<Prompt> prompt) {
702 DCHECK(ui_loop_ == base::MessageLoop::current());
703 extension_ = extension;
704 delegate_ = delegate;
705 prompt_ = prompt;
707 SetIcon(icon);
708 ShowConfirmation();
711 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
712 Delegate* delegate,
713 const Extension* extension,
714 const SkBitmap* icon,
715 const ShowDialogCallback& show_dialog_callback) {
716 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
717 // remaining fields.
718 extension_ = extension;
719 SetIcon(icon);
720 ConfirmInstall(delegate, extension, show_dialog_callback);
723 void ExtensionInstallPrompt::ConfirmInstall(
724 Delegate* delegate,
725 const Extension* extension,
726 const ShowDialogCallback& show_dialog_callback) {
727 DCHECK(ui_loop_ == base::MessageLoop::current());
728 extension_ = extension;
729 delegate_ = delegate;
730 prompt_ = new Prompt(INSTALL_PROMPT);
731 show_dialog_callback_ = show_dialog_callback;
733 // We special-case themes to not show any confirm UI. Instead they are
734 // immediately installed, and then we show an infobar (see OnInstallSuccess)
735 // to allow the user to revert if they don't like it.
737 // We don't do this in the case where off-store extension installs are
738 // disabled because in that case, we don't show the dangerous download UI, so
739 // we need the UI confirmation.
740 if (extension->is_theme()) {
741 if (extension->from_webstore() ||
742 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
743 delegate->InstallUIProceed();
744 return;
748 LoadImageIfNeeded();
751 void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
752 const Extension* extension) {
753 DCHECK(ui_loop_ == base::MessageLoop::current());
754 extension_ = extension;
755 delegate_ = delegate;
756 bool is_remote_install =
757 profile_ &&
758 extensions::ExtensionPrefs::Get(profile_)->HasDisableReason(
759 extension->id(), extensions::Extension::DISABLE_REMOTE_INSTALL);
760 bool is_ephemeral =
761 extensions::util::IsEphemeralApp(extension->id(), profile_);
763 PromptType type = UNSET_PROMPT_TYPE;
764 if (is_ephemeral)
765 type = LAUNCH_PROMPT;
766 else if (is_remote_install)
767 type = REMOTE_INSTALL_PROMPT;
768 else
769 type = RE_ENABLE_PROMPT;
770 prompt_ = new Prompt(type);
772 LoadImageIfNeeded();
775 void ExtensionInstallPrompt::ConfirmExternalInstall(
776 Delegate* delegate,
777 const Extension* extension,
778 const ShowDialogCallback& show_dialog_callback,
779 scoped_refptr<Prompt> prompt) {
780 DCHECK(ui_loop_ == base::MessageLoop::current());
781 extension_ = extension;
782 delegate_ = delegate;
783 prompt_ = prompt;
784 show_dialog_callback_ = show_dialog_callback;
786 LoadImageIfNeeded();
789 void ExtensionInstallPrompt::ConfirmPermissions(
790 Delegate* delegate,
791 const Extension* extension,
792 const PermissionSet* permissions) {
793 DCHECK(ui_loop_ == base::MessageLoop::current());
794 extension_ = extension;
795 custom_permissions_ = permissions;
796 delegate_ = delegate;
797 prompt_ = new Prompt(PERMISSIONS_PROMPT);
799 LoadImageIfNeeded();
802 void ExtensionInstallPrompt::ReviewPermissions(
803 Delegate* delegate,
804 const Extension* extension,
805 const std::vector<base::FilePath>& retained_file_paths,
806 const std::vector<base::string16>& retained_device_messages) {
807 DCHECK(ui_loop_ == base::MessageLoop::current());
808 extension_ = extension;
809 prompt_ = new Prompt(POST_INSTALL_PERMISSIONS_PROMPT);
810 prompt_->set_retained_files(retained_file_paths);
811 prompt_->set_retained_device_messages(retained_device_messages);
812 delegate_ = delegate;
814 LoadImageIfNeeded();
817 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
818 SkBitmap* icon) {
819 extension_ = extension;
820 SetIcon(icon);
822 install_ui_->OnInstallSuccess(extension, &icon_);
825 void ExtensionInstallPrompt::OnInstallFailure(
826 const extensions::CrxInstallerError& error) {
827 install_ui_->OnInstallFailure(error);
830 void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
831 if (image)
832 icon_ = *image;
833 else
834 icon_ = SkBitmap();
835 if (icon_.empty()) {
836 // Let's set default icon bitmap whose size is equal to the default icon's
837 // pixel size under maximal supported scale factor. If the bitmap is larger
838 // than the one we need, it will be scaled down by the ui code.
839 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
843 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
844 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
845 ShowConfirmation();
848 void ExtensionInstallPrompt::LoadImageIfNeeded() {
849 // Bundle install prompts do not have an icon.
850 // Also |profile_| can be NULL in unit tests.
851 if (!icon_.empty() || !profile_) {
852 ShowConfirmation();
853 return;
856 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
857 extension_,
858 extension_misc::EXTENSION_ICON_LARGE,
859 ExtensionIconSet::MATCH_BIGGER);
861 // Load the image asynchronously. The response will be sent to OnImageLoaded.
862 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile_);
864 std::vector<extensions::ImageLoader::ImageRepresentation> images_list;
865 images_list.push_back(extensions::ImageLoader::ImageRepresentation(
866 image,
867 extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE,
868 gfx::Size(),
869 ui::SCALE_FACTOR_100P));
870 loader->LoadImagesAsync(
871 extension_,
872 images_list,
873 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
876 void ExtensionInstallPrompt::ShowConfirmation() {
877 if (prompt_->type() == INSTALL_PROMPT)
878 prompt_->set_experiment(ExtensionInstallPromptExperiment::Find());
879 else
880 prompt_->set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
882 scoped_refptr<const PermissionSet> permissions_to_display;
883 if (custom_permissions_.get()) {
884 permissions_to_display = custom_permissions_;
885 } else if (extension_) {
886 // Initialize permissions if they have not already been set so that
887 // withheld permissions are displayed properly in the install prompt.
888 extensions::PermissionsUpdater(
889 profile_, extensions::PermissionsUpdater::INIT_FLAG_TRANSIENT)
890 .InitializePermissions(extension_);
891 permissions_to_display =
892 extension_->permissions_data()->active_permissions();
895 if (permissions_to_display.get() &&
896 (!extension_ ||
897 !extensions::PermissionsData::ShouldSkipPermissionWarnings(
898 extension_->id()))) {
899 Manifest::Type type =
900 extension_ ? extension_->GetType() : Manifest::TYPE_UNKNOWN;
901 const extensions::PermissionMessageProvider* message_provider =
902 extensions::PermissionMessageProvider::Get();
903 prompt_->SetPermissions(message_provider->GetWarningMessages(
904 permissions_to_display.get(), type),
905 REGULAR_PERMISSIONS);
906 prompt_->SetPermissionsDetails(message_provider->GetWarningMessagesDetails(
907 permissions_to_display.get(), type),
908 REGULAR_PERMISSIONS);
910 scoped_refptr<const extensions::PermissionSet> withheld =
911 extension_->permissions_data()->withheld_permissions();
912 if (!withheld->IsEmpty()) {
913 prompt_->SetPermissions(
914 message_provider->GetWarningMessages(withheld.get(), type),
915 PermissionsType::WITHHELD_PERMISSIONS);
916 prompt_->SetPermissionsDetails(
917 message_provider->GetWarningMessagesDetails(withheld.get(), type),
918 PermissionsType::WITHHELD_PERMISSIONS);
922 switch (prompt_->type()) {
923 case PERMISSIONS_PROMPT:
924 case RE_ENABLE_PROMPT:
925 case INLINE_INSTALL_PROMPT:
926 case EXTERNAL_INSTALL_PROMPT:
927 case INSTALL_PROMPT:
928 case LAUNCH_PROMPT:
929 case POST_INSTALL_PERMISSIONS_PROMPT:
930 case REMOTE_INSTALL_PROMPT:
931 case REPAIR_PROMPT: {
932 prompt_->set_extension(extension_);
933 prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
934 break;
936 case BUNDLE_INSTALL_PROMPT: {
937 prompt_->set_bundle(bundle_);
938 break;
940 default:
941 NOTREACHED() << "Unknown message";
942 return;
945 if (AutoConfirmPrompt(delegate_))
946 return;
948 if (show_dialog_callback_.is_null())
949 GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
950 else
951 show_dialog_callback_.Run(show_params_, delegate_, prompt_);