Home | History | Annotate | Download | only in extensions
      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       (!extension_ ||
    717        !extensions::PermissionsData::ShouldSkipPermissionWarnings(
    718            extension_->id()))) {
    719     Manifest::Type type =
    720         extension_ ? extension_->GetType() : Manifest::TYPE_UNKNOWN;
    721     const extensions::PermissionMessageProvider* message_provider =
    722         extensions::PermissionMessageProvider::Get();
    723     prompt_->SetPermissions(
    724         message_provider->GetWarningMessages(permissions_, type));
    725     prompt_->SetPermissionsDetails(
    726         message_provider->GetWarningMessagesDetails(permissions_, type));
    727   }
    728 
    729   switch (prompt_->type()) {
    730     case PERMISSIONS_PROMPT:
    731     case RE_ENABLE_PROMPT:
    732     case INLINE_INSTALL_PROMPT:
    733     case EXTERNAL_INSTALL_PROMPT:
    734     case INSTALL_PROMPT:
    735     case LAUNCH_PROMPT:
    736     case POST_INSTALL_PERMISSIONS_PROMPT:
    737     case REMOTE_INSTALL_PROMPT: {
    738       prompt_->set_extension(extension_);
    739       prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
    740       break;
    741     }
    742     case BUNDLE_INSTALL_PROMPT: {
    743       prompt_->set_bundle(bundle_);
    744       break;
    745     }
    746     default:
    747       NOTREACHED() << "Unknown message";
    748       return;
    749   }
    750 
    751   if (AutoConfirmPrompt(delegate_))
    752     return;
    753 
    754   if (show_dialog_callback_.is_null())
    755     GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
    756   else
    757     show_dialog_callback_.Run(show_params_, delegate_, prompt_);
    758 }
    759