074b0469582a8b0eeeca7e7cfed6f20f8b0b4ec3
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_install_prompt.cc
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.
4
5 #include "chrome/browser/extensions/extension_install_prompt.h"
6
7 #include <map>
8
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_install_ui.h"
18 #include "chrome/browser/extensions/extension_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h"
24 #include "content/public/browser/web_contents.h"
25 #include "extensions/browser/extension_prefs.h"
26 #include "extensions/browser/extension_util.h"
27 #include "extensions/browser/image_loader.h"
28 #include "extensions/common/constants.h"
29 #include "extensions/common/extension.h"
30 #include "extensions/common/extension_icon_set.h"
31 #include "extensions/common/extension_resource.h"
32 #include "extensions/common/feature_switch.h"
33 #include "extensions/common/manifest.h"
34 #include "extensions/common/manifest_constants.h"
35 #include "extensions/common/manifest_handlers/icons_handler.h"
36 #include "extensions/common/permissions/permission_message_provider.h"
37 #include "extensions/common/permissions/permission_set.h"
38 #include "extensions/common/permissions/permissions_data.h"
39 #include "extensions/common/url_pattern.h"
40 #include "grit/chromium_strings.h"
41 #include "grit/generated_resources.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/gfx/image/image.h"
46
47 using extensions::BundleInstaller;
48 using extensions::Extension;
49 using extensions::Manifest;
50 using extensions::PermissionSet;
51
52 namespace {
53
54 static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
55     0,  // The regular install prompt depends on what's being installed.
56     IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
57     IDS_EXTENSION_INSTALL_PROMPT_TITLE,
58     IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
59     IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
60     IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
61     IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
62     IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE,
63     0,  // The remote install prompt depends on what's being installed.
64 };
65 static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
66     IDS_EXTENSION_INSTALL_PROMPT_HEADING,
67     0,  // Inline installs use the extension name.
68     0,  // Heading for bundle installs depends on the bundle contents.
69     IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
70     IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
71     0,  // External installs use different strings for extensions/apps.
72     IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
73     IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING,
74     IDS_EXTENSION_REMOTE_INSTALL_PROMPT_HEADING,
75 };
76 static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
77     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
78     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
79     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
80     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
81     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
82     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
83     ui::DIALOG_BUTTON_CANCEL,
84     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
85     ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
86 };
87 static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
88     IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
89     IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
90     IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
91     IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
92     IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
93     0,  // External installs use different strings for extensions/apps.
94     IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON,
95     IDS_EXTENSION_PROMPT_LAUNCH_BUTTON,
96     IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON,
97 };
98 static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
99     0,  // These all use the platform's default cancel label.
100     0,
101     0,
102     0,
103     IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
104     IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
105     IDS_CLOSE,
106     0,  // Platform dependent cancel button.
107     0,
108 };
109 static const int
110     kPermissionsHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
111         IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
112         IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
113         IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
114         IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
115         IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
116         IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
117         IDS_EXTENSION_PROMPT_CAN_ACCESS,
118         IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
119         IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
120 };
121
122 // Returns bitmap for the default icon with size equal to the default icon's
123 // pixel size under maximal supported scale factor.
124 SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
125   const gfx::ImageSkia& image = is_app ?
126       extensions::util::GetDefaultAppIcon() :
127       extensions::util::GetDefaultExtensionIcon();
128   return image.GetRepresentation(
129       gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
130 }
131
132 // If auto confirm is enabled then posts a task to proceed with or cancel the
133 // install and returns true. Otherwise returns false.
134 bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
135   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
136   if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests))
137     return false;
138   std::string value = cmdline->GetSwitchValueASCII(
139       switches::kAppsGalleryInstallAutoConfirmForTests);
140
141   // We use PostTask instead of calling the delegate directly here, because in
142   // the real implementations it's highly likely the message loop will be
143   // pumping a few times before the user clicks accept or cancel.
144   if (value == "accept") {
145     base::MessageLoop::current()->PostTask(
146         FROM_HERE,
147         base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
148                    base::Unretained(delegate)));
149     return true;
150   }
151
152   if (value == "cancel") {
153     base::MessageLoop::current()->PostTask(
154         FROM_HERE,
155         base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
156                    base::Unretained(delegate),
157                    true));
158     return true;
159   }
160
161   NOTREACHED();
162   return false;
163 }
164
165 Profile* ProfileForWebContents(content::WebContents* web_contents) {
166   if (!web_contents)
167     return NULL;
168   return Profile::FromBrowserContext(web_contents->GetBrowserContext());
169 }
170
171 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
172   if (!contents)
173     return NULL;
174
175   return contents->GetTopLevelNativeWindow();
176 }
177
178 }  // namespace
179
180 ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
181     : type_(type),
182       is_showing_details_for_retained_files_(false),
183       extension_(NULL),
184       bundle_(NULL),
185       average_rating_(0.0),
186       rating_count_(0),
187       show_user_count_(false),
188       has_webstore_data_(false) {
189 }
190
191 ExtensionInstallPrompt::Prompt::~Prompt() {
192 }
193
194 void ExtensionInstallPrompt::Prompt::SetPermissions(
195     const std::vector<base::string16>& permissions) {
196   permissions_ = permissions;
197 }
198
199 void ExtensionInstallPrompt::Prompt::SetPermissionsDetails(
200     const std::vector<base::string16>& details) {
201   details_ = details;
202   is_showing_details_for_permissions_.clear();
203   for (size_t i = 0; i < details.size(); ++i)
204     is_showing_details_for_permissions_.push_back(false);
205 }
206
207 void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
208     DetailsType type,
209     size_t index,
210     bool is_showing_details) {
211   switch (type) {
212     case PERMISSIONS_DETAILS:
213       is_showing_details_for_permissions_[index] = is_showing_details;
214       break;
215     case RETAINED_FILES_DETAILS:
216       is_showing_details_for_retained_files_ = is_showing_details;
217       break;
218   }
219 }
220
221 void ExtensionInstallPrompt::Prompt::SetWebstoreData(
222     const std::string& localized_user_count,
223     bool show_user_count,
224     double average_rating,
225     int rating_count) {
226   CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
227   localized_user_count_ = localized_user_count;
228   show_user_count_ = show_user_count;
229   average_rating_ = average_rating;
230   rating_count_ = rating_count;
231   has_webstore_data_ = true;
232 }
233
234 base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
235   int resource_id = kTitleIds[type_];
236
237   if (type_ == INSTALL_PROMPT) {
238     if (extension_->is_app())
239       resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
240     else if (extension_->is_theme())
241       resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
242     else
243       resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
244   } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
245     return l10n_util::GetStringFUTF16(
246         resource_id, base::UTF8ToUTF16(extension_->name()));
247   } else if (type_ == REMOTE_INSTALL_PROMPT) {
248     if (extension_->is_app())
249       resource_id = IDS_EXTENSION_REMOTE_INSTALL_APP_PROMPT_TITLE;
250     else
251       resource_id = IDS_EXTENSION_REMOTE_INSTALL_EXTENSION_PROMPT_TITLE;
252   }
253
254   return l10n_util::GetStringUTF16(resource_id);
255 }
256
257 base::string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
258   if (type_ == INLINE_INSTALL_PROMPT) {
259     return base::UTF8ToUTF16(extension_->name());
260   } else if (type_ == BUNDLE_INSTALL_PROMPT) {
261     return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
262   } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
263     int resource_id = -1;
264     if (extension_->is_app())
265       resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
266     else if (extension_->is_theme())
267       resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
268     else
269       resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
270     return l10n_util::GetStringUTF16(resource_id);
271   } else {
272     return l10n_util::GetStringFUTF16(
273         kHeadingIds[type_], base::UTF8ToUTF16(extension_->name()));
274   }
275 }
276
277 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
278   if (type_ == POST_INSTALL_PERMISSIONS_PROMPT &&
279       ShouldDisplayRevokeFilesButton()) {
280     return kButtons[type_] | ui::DIALOG_BUTTON_OK;
281   }
282
283   return kButtons[type_];
284 }
285
286 bool ExtensionInstallPrompt::Prompt::ShouldShowExplanationText() const {
287    return type_ == INSTALL_PROMPT &&
288        extension_->is_extension() && experiment_ && experiment_->text_only();
289 }
290
291 bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const {
292   if (kAcceptButtonIds[type_] == 0)
293     return false;
294
295   if (type_ == POST_INSTALL_PERMISSIONS_PROMPT)
296     return ShouldDisplayRevokeFilesButton();
297
298   return true;
299 }
300
301 base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
302   if (type_ == EXTERNAL_INSTALL_PROMPT) {
303     int id = -1;
304     if (extension_->is_app())
305       id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
306     else if (extension_->is_theme())
307       id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
308     else
309       id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
310     return l10n_util::GetStringUTF16(id);
311   }
312   if (ShouldShowExplanationText())
313     return experiment_->GetOkButtonText();
314   return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
315 }
316
317 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
318   if (ShouldShowExplanationText())
319     return true;
320   return kAbortButtonIds[type_] > 0;
321 }
322
323 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
324   CHECK(HasAbortButtonLabel());
325   if (ShouldShowExplanationText())
326     return experiment_->GetCancelButtonText();
327   return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
328 }
329
330 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
331   return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
332 }
333
334 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
335   const int kRetainedFilesMessageIDs[6] = {
336       IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT,
337       IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR,
338       IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO,
339       IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO,
340       IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW,
341       IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY,
342   };
343   std::vector<int> message_ids;
344   for (size_t i = 0; i < arraysize(kRetainedFilesMessageIDs); i++) {
345     message_ids.push_back(kRetainedFilesMessageIDs[i]);
346   }
347   return l10n_util::GetPluralStringFUTF16(message_ids, GetRetainedFileCount());
348 }
349
350 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
351   return GetPermissionCount() > 0 || type_ == POST_INSTALL_PERMISSIONS_PROMPT;
352 }
353
354 void ExtensionInstallPrompt::Prompt::AppendRatingStars(
355     StarAppender appender, void* data) const {
356   CHECK(appender);
357   CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
358   int rating_integer = floor(average_rating_);
359   double rating_fractional = average_rating_ - rating_integer;
360
361   if (rating_fractional > 0.66) {
362     rating_integer++;
363   }
364
365   if (rating_fractional < 0.33 || rating_fractional > 0.66) {
366     rating_fractional = 0;
367   }
368
369   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
370   int i;
371   for (i = 0; i < rating_integer; i++) {
372     appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
373   }
374   if (rating_fractional) {
375     appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
376     i++;
377   }
378   for (; i < kMaxExtensionRating; i++) {
379     appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
380   }
381 }
382
383 base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
384   CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
385   return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
386                                     base::IntToString16(rating_count_));
387 }
388
389 base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
390   CHECK(type_ == INLINE_INSTALL_PROMPT || type_ == EXTERNAL_INSTALL_PROMPT);
391
392   if (show_user_count_) {
393     return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
394                                       base::UTF8ToUTF16(localized_user_count_));
395   }
396   return base::string16();
397 }
398
399 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
400   return permissions_.size();
401 }
402
403 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount() const {
404   return details_.size();
405 }
406
407 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index)
408     const {
409   CHECK_LT(index, permissions_.size());
410   return permissions_[index];
411 }
412
413 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
414     size_t index) const {
415   CHECK_LT(index, details_.size());
416   return details_[index];
417 }
418
419 bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
420     DetailsType type, size_t index) const {
421   switch (type) {
422     case PERMISSIONS_DETAILS:
423       CHECK_LT(index, is_showing_details_for_permissions_.size());
424       return is_showing_details_for_permissions_[index];
425     case RETAINED_FILES_DETAILS:
426       return is_showing_details_for_retained_files_;
427   }
428   return false;
429 }
430
431 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
432   return retained_files_.size();
433 }
434
435 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
436     const {
437   CHECK_LT(index, retained_files_.size());
438   return retained_files_[index].AsUTF16Unsafe();
439 }
440
441 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
442   return !retained_files_.empty();
443 }
444
445 ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
446     : parent_web_contents(contents),
447       parent_window(NativeWindowForWebContents(contents)),
448       navigator(contents) {
449 }
450
451 ExtensionInstallPrompt::ShowParams::ShowParams(
452     gfx::NativeWindow window,
453     content::PageNavigator* navigator)
454     : parent_web_contents(NULL),
455       parent_window(window),
456       navigator(navigator) {
457 }
458
459 // static
460 scoped_refptr<Extension>
461     ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
462     const base::DictionaryValue* manifest,
463     int flags,
464     const std::string& id,
465     const std::string& localized_name,
466     const std::string& localized_description,
467     std::string* error) {
468   scoped_ptr<base::DictionaryValue> localized_manifest;
469   if (!localized_name.empty() || !localized_description.empty()) {
470     localized_manifest.reset(manifest->DeepCopy());
471     if (!localized_name.empty()) {
472       localized_manifest->SetString(extensions::manifest_keys::kName,
473                                     localized_name);
474     }
475     if (!localized_description.empty()) {
476       localized_manifest->SetString(extensions::manifest_keys::kDescription,
477                                     localized_description);
478     }
479   }
480
481   return Extension::Create(
482       base::FilePath(),
483       Manifest::INTERNAL,
484       localized_manifest.get() ? *localized_manifest.get() : *manifest,
485       flags,
486       id,
487       error);
488 }
489
490 ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents)
491     : ui_loop_(base::MessageLoop::current()),
492       extension_(NULL),
493       bundle_(NULL),
494       install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))),
495       show_params_(contents),
496       delegate_(NULL) {
497 }
498
499 ExtensionInstallPrompt::ExtensionInstallPrompt(
500     Profile* profile,
501     gfx::NativeWindow native_window,
502     content::PageNavigator* navigator)
503     : ui_loop_(base::MessageLoop::current()),
504       extension_(NULL),
505       bundle_(NULL),
506       install_ui_(ExtensionInstallUI::Create(profile)),
507       show_params_(native_window, navigator),
508       delegate_(NULL) {
509 }
510
511 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
512 }
513
514 void ExtensionInstallPrompt::ConfirmBundleInstall(
515     extensions::BundleInstaller* bundle,
516     const PermissionSet* permissions) {
517   DCHECK(ui_loop_ == base::MessageLoop::current());
518   bundle_ = bundle;
519   permissions_ = permissions;
520   delegate_ = bundle;
521   prompt_ = new Prompt(BUNDLE_INSTALL_PROMPT);
522
523   ShowConfirmation();
524 }
525
526 void ExtensionInstallPrompt::ConfirmStandaloneInstall(
527     Delegate* delegate,
528     const Extension* extension,
529     SkBitmap* icon,
530     scoped_refptr<Prompt> prompt) {
531   DCHECK(ui_loop_ == base::MessageLoop::current());
532   extension_ = extension;
533   permissions_ = extension->permissions_data()->active_permissions();
534   delegate_ = delegate;
535   prompt_ = prompt;
536
537   SetIcon(icon);
538   ShowConfirmation();
539 }
540
541 void ExtensionInstallPrompt::ConfirmWebstoreInstall(
542     Delegate* delegate,
543     const Extension* extension,
544     const SkBitmap* icon,
545     const ShowDialogCallback& show_dialog_callback) {
546   // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
547   // remaining fields.
548   extension_ = extension;
549   SetIcon(icon);
550   ConfirmInstall(delegate, extension, show_dialog_callback);
551 }
552
553 void ExtensionInstallPrompt::ConfirmInstall(
554     Delegate* delegate,
555     const Extension* extension,
556     const ShowDialogCallback& show_dialog_callback) {
557   DCHECK(ui_loop_ == base::MessageLoop::current());
558   extension_ = extension;
559   permissions_ = extension->permissions_data()->active_permissions();
560   delegate_ = delegate;
561   prompt_ = new Prompt(INSTALL_PROMPT);
562   show_dialog_callback_ = show_dialog_callback;
563
564   // We special-case themes to not show any confirm UI. Instead they are
565   // immediately installed, and then we show an infobar (see OnInstallSuccess)
566   // to allow the user to revert if they don't like it.
567   //
568   // We don't do this in the case where off-store extension installs are
569   // disabled because in that case, we don't show the dangerous download UI, so
570   // we need the UI confirmation.
571   if (extension->is_theme()) {
572     if (extension->from_webstore() ||
573         extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
574       delegate->InstallUIProceed();
575       return;
576     }
577   }
578
579   LoadImageIfNeeded();
580 }
581
582 void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
583                                              const Extension* extension) {
584   DCHECK(ui_loop_ == base::MessageLoop::current());
585   extension_ = extension;
586   permissions_ = extension->permissions_data()->active_permissions();
587   delegate_ = delegate;
588   bool is_remote_install =
589       install_ui_->profile() &&
590       extensions::ExtensionPrefs::Get(install_ui_->profile())->HasDisableReason(
591           extension->id(), extensions::Extension::DISABLE_REMOTE_INSTALL);
592   bool is_ephemeral =
593       extensions::util::IsEphemeralApp(extension->id(), install_ui_->profile());
594
595   PromptType type = UNSET_PROMPT_TYPE;
596   if (is_ephemeral)
597     type = LAUNCH_PROMPT;
598   else if (is_remote_install)
599     type = REMOTE_INSTALL_PROMPT;
600   else
601     type = RE_ENABLE_PROMPT;
602   prompt_ = new Prompt(type);
603
604   LoadImageIfNeeded();
605 }
606
607 void ExtensionInstallPrompt::ConfirmExternalInstall(
608     Delegate* delegate,
609     const Extension* extension,
610     const ShowDialogCallback& show_dialog_callback,
611     scoped_refptr<Prompt> prompt) {
612   DCHECK(ui_loop_ == base::MessageLoop::current());
613   extension_ = extension;
614   permissions_ = extension->permissions_data()->active_permissions();
615   delegate_ = delegate;
616   prompt_ = prompt;
617   show_dialog_callback_ = show_dialog_callback;
618
619   LoadImageIfNeeded();
620 }
621
622 void ExtensionInstallPrompt::ConfirmPermissions(
623     Delegate* delegate,
624     const Extension* extension,
625     const PermissionSet* permissions) {
626   DCHECK(ui_loop_ == base::MessageLoop::current());
627   extension_ = extension;
628   permissions_ = permissions;
629   delegate_ = delegate;
630   prompt_ = new Prompt(PERMISSIONS_PROMPT);
631
632   LoadImageIfNeeded();
633 }
634
635 void ExtensionInstallPrompt::ReviewPermissions(
636     Delegate* delegate,
637     const Extension* extension,
638     const std::vector<base::FilePath>& retained_file_paths) {
639   DCHECK(ui_loop_ == base::MessageLoop::current());
640   extension_ = extension;
641   permissions_ = extension->permissions_data()->active_permissions();
642   prompt_ = new Prompt(POST_INSTALL_PERMISSIONS_PROMPT);
643   prompt_->set_retained_files(retained_file_paths);
644   delegate_ = delegate;
645
646   LoadImageIfNeeded();
647 }
648
649 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
650                                               SkBitmap* icon) {
651   extension_ = extension;
652   SetIcon(icon);
653
654   install_ui_->OnInstallSuccess(extension, &icon_);
655 }
656
657 void ExtensionInstallPrompt::OnInstallFailure(
658     const extensions::CrxInstallerError& error) {
659   install_ui_->OnInstallFailure(error);
660 }
661
662 void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
663   if (image)
664     icon_ = *image;
665   else
666     icon_ = SkBitmap();
667   if (icon_.empty()) {
668     // Let's set default icon bitmap whose size is equal to the default icon's
669     // pixel size under maximal supported scale factor. If the bitmap is larger
670     // than the one we need, it will be scaled down by the ui code.
671     icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
672   }
673 }
674
675 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
676   SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
677   ShowConfirmation();
678 }
679
680 void ExtensionInstallPrompt::LoadImageIfNeeded() {
681   // Bundle install prompts do not have an icon.
682   // Also |install_ui_.profile()| can be NULL in unit tests.
683   if (!icon_.empty() || !install_ui_->profile()) {
684     ShowConfirmation();
685     return;
686   }
687
688   extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
689       extension_,
690       extension_misc::EXTENSION_ICON_LARGE,
691       ExtensionIconSet::MATCH_BIGGER);
692
693   // Load the image asynchronously. The response will be sent to OnImageLoaded.
694   extensions::ImageLoader* loader =
695       extensions::ImageLoader::Get(install_ui_->profile());
696
697   std::vector<extensions::ImageLoader::ImageRepresentation> images_list;
698   images_list.push_back(extensions::ImageLoader::ImageRepresentation(
699       image,
700       extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE,
701       gfx::Size(),
702       ui::SCALE_FACTOR_100P));
703   loader->LoadImagesAsync(
704       extension_,
705       images_list,
706       base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
707 }
708
709 void ExtensionInstallPrompt::ShowConfirmation() {
710   if (prompt_->type() == INSTALL_PROMPT)
711     prompt_->set_experiment(ExtensionInstallPromptExperiment::Find());
712   else
713     prompt_->set_experiment(ExtensionInstallPromptExperiment::ControlGroup());
714
715   if (permissions_.get()) {
716     if (extension_) {
717       const extensions::PermissionsData* permissions_data =
718           extension_->permissions_data();
719       prompt_->SetPermissions(permissions_data->GetPermissionMessageStrings());
720       prompt_->SetPermissionsDetails(
721           permissions_data->GetPermissionMessageDetailsStrings());
722     } else {
723       const extensions::PermissionMessageProvider* message_provider =
724           extensions::PermissionMessageProvider::Get();
725       prompt_->SetPermissions(message_provider->GetWarningMessages(
726           permissions_, Manifest::TYPE_UNKNOWN));
727       prompt_->SetPermissionsDetails(
728           message_provider->GetWarningMessagesDetails(permissions_,
729                                                       Manifest::TYPE_UNKNOWN));
730     }
731   }
732
733   switch (prompt_->type()) {
734     case PERMISSIONS_PROMPT:
735     case RE_ENABLE_PROMPT:
736     case INLINE_INSTALL_PROMPT:
737     case EXTERNAL_INSTALL_PROMPT:
738     case INSTALL_PROMPT:
739     case LAUNCH_PROMPT:
740     case POST_INSTALL_PERMISSIONS_PROMPT:
741     case REMOTE_INSTALL_PROMPT: {
742       prompt_->set_extension(extension_);
743       prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
744       break;
745     }
746     case BUNDLE_INSTALL_PROMPT: {
747       prompt_->set_bundle(bundle_);
748       break;
749     }
750     default:
751       NOTREACHED() << "Unknown message";
752       return;
753   }
754
755   if (AutoConfirmPrompt(delegate_))
756     return;
757
758   if (show_dialog_callback_.is_null())
759     GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
760   else
761     show_dialog_callback_.Run(show_params_, delegate_, prompt_);
762 }