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